jekyll-theme-guides-mbland 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/jekyll-theme-guides-mbland.rb +10 -0
- data/lib/jekyll-theme-guides-mbland/breadcrumbs.rb +28 -0
- data/lib/jekyll-theme-guides-mbland/generated_nodes.rb +64 -0
- data/lib/jekyll-theme-guides-mbland/generated_pages.rb +36 -0
- data/lib/jekyll-theme-guides-mbland/generator.rb +17 -0
- data/lib/jekyll-theme-guides-mbland/namespace_flattener.rb +39 -0
- data/lib/jekyll-theme-guides-mbland/navigation.rb +257 -0
- data/lib/jekyll-theme-guides-mbland/repository.rb +73 -0
- data/lib/jekyll-theme-guides-mbland/tags.rb +51 -0
- data/lib/jekyll-theme-guides-mbland/update.rb +6 -0
- data/lib/jekyll-theme-guides-mbland/version.rb +3 -0
- metadata +12 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 29934a58f4e2a89479b2df4e2d399ad911a8e854
|
4
|
+
data.tar.gz: 47be69db1434d7b7b57ac129f30d2f8354a4dd7b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c226a22e83ede73c78f45e96e395ad21143e80483e3e52649f9237fa1391448fc7d987e0e9383660be884ca910c999b0900863f56a5d5ff958d6376cc6c2127f
|
7
|
+
data.tar.gz: 63363244938c0a3d5d5a5cc032dd22230062909cc11a3e898e159b2d86e5c1c2966369c77b1e7b64cd9ea6ee932eb92c35cf4133ae5d261cb716ded568a843f4
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'jekyll-theme-guides-mbland/breadcrumbs'
|
2
|
+
require 'jekyll-theme-guides-mbland/generator'
|
3
|
+
require 'jekyll-theme-guides-mbland/navigation'
|
4
|
+
require 'jekyll-theme-guides-mbland/repository'
|
5
|
+
require 'jekyll-theme-guides-mbland/tags'
|
6
|
+
require 'jekyll-theme-guides-mbland/update'
|
7
|
+
require 'jekyll-theme-guides-mbland/version'
|
8
|
+
|
9
|
+
require 'jekyll_pages_api'
|
10
|
+
require 'jekyll_pages_api_search'
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'jekyll'
|
2
|
+
require 'safe_yaml'
|
3
|
+
|
4
|
+
module JekyllThemeGuidesMbland
|
5
|
+
class Breadcrumbs
|
6
|
+
def self.generate(site, docs)
|
7
|
+
breadcrumbs = create_breadcrumbs(site)
|
8
|
+
docs.each do |page|
|
9
|
+
page.data['breadcrumbs'] = breadcrumbs[page.permalink || page.url]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.create_breadcrumbs(site)
|
14
|
+
(site.config['navigation'] || []).flat_map do |nav|
|
15
|
+
Breadcrumbs.generate_breadcrumbs(nav, '/', [])
|
16
|
+
end.to_h
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.generate_breadcrumbs(nav, parent_url, parents)
|
20
|
+
url = parent_url + (nav['url'] || '')
|
21
|
+
crumbs = parents + [{ 'url' => url, 'text' => nav['text'] }]
|
22
|
+
child_crumbs = (nav['children'] || []).flat_map do |child|
|
23
|
+
generate_breadcrumbs(child, url, crumbs)
|
24
|
+
end
|
25
|
+
[[url, crumbs]] + child_crumbs
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module JekyllThemeGuidesMbland
|
2
|
+
class GeneratedNodes
|
3
|
+
# Params:
|
4
|
+
# url_to_nav: Mapping from original document URL to "nav item" objects,
|
5
|
+
# i.e. { 'text' => '...', 'url' => '...', 'internal' => true }
|
6
|
+
# nav_data: Array of nav item objects contained in `url_to_nav` after
|
7
|
+
# applying updates, possibly containing "orphan" items marked with an
|
8
|
+
# `:orphan_url` property
|
9
|
+
#
|
10
|
+
# Returns:
|
11
|
+
# nav_data with orphans properly nested within automatically-generated
|
12
|
+
# parent nodes marked with `'generated' => true`
|
13
|
+
def self.create_homes_for_orphans(url_to_nav, nav_data)
|
14
|
+
orphans = nav_data.select { |nav| nav[:orphan_url] }
|
15
|
+
orphans.each { |nav| create_home_for_orphan(nav, nav_data, url_to_nav) }
|
16
|
+
nav_data.reject! { |nav| nav[:orphan_url] }
|
17
|
+
prune_childless_parents(nav_data)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.create_home_for_orphan(nav, nav_data, url_to_nav)
|
21
|
+
parents = nav[:orphan_url].split('/')[1..-1]
|
22
|
+
nav['url'] = parents.pop + '/'
|
23
|
+
child_url = '/'
|
24
|
+
immediate_parent = parents.reduce(nil) do |parent, child|
|
25
|
+
child_url = child_url + child + '/'
|
26
|
+
find_or_create_node(nav_data, child_url, parent, child, url_to_nav)
|
27
|
+
end
|
28
|
+
assign_orphan_to_home(nav, immediate_parent, url_to_nav)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.find_or_create_node(nav_data, child_url, parent, child, url_to_nav)
|
32
|
+
child_nav = url_to_nav[child_url]
|
33
|
+
if child_nav.nil?
|
34
|
+
child_nav = generated_node(child)
|
35
|
+
url_to_nav[child_url] = child_nav
|
36
|
+
(parent.nil? ? nav_data : (parent['children'] ||= [])) << child_nav
|
37
|
+
end
|
38
|
+
child_nav
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.generated_node(parent_slug)
|
42
|
+
{
|
43
|
+
'text' => parent_slug.split('-').join(' ').capitalize,
|
44
|
+
'url' => parent_slug + '/',
|
45
|
+
'internal' => true,
|
46
|
+
'generated' => true,
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.assign_orphan_to_home(nav, immediate_parent, url_to_nav)
|
51
|
+
nav_copy = {}.merge(nav)
|
52
|
+
url_to_nav[nav_copy.delete(:orphan_url)] = nav_copy
|
53
|
+
(immediate_parent['children'] ||= []) << nav_copy
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.prune_childless_parents(nav_data)
|
57
|
+
(nav_data || []).reject! do |nav|
|
58
|
+
children = (nav['children'] || [])
|
59
|
+
prune_childless_parents(children)
|
60
|
+
nav['generated'] && children.empty?
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module JekyllThemeGuidesMbland
|
2
|
+
class GeneratedPages
|
3
|
+
DEFAULT_LAYOUT = 'jekyll_theme_guides_mbland_generated_home_redirect'.freeze
|
4
|
+
|
5
|
+
def self.generate_pages_from_navigation_data(site)
|
6
|
+
layout = site.config['generate_nodes']
|
7
|
+
return if layout.nil? || layout == false
|
8
|
+
layout = DEFAULT_LAYOUT if layout == true
|
9
|
+
nav_data = site.config['navigation']
|
10
|
+
generate_pages_from_generated_nodes(site, layout, nav_data, '/')
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.generate_pages_from_generated_nodes(site, layout, nav_data,
|
14
|
+
parent_url)
|
15
|
+
(nav_data || []).select { |nav| nav['generated'] }.each do |nav|
|
16
|
+
site.pages << GeneratedPage.new(site, layout, nav, parent_url)
|
17
|
+
children = nav['children']
|
18
|
+
next_url = parent_url + nav['url']
|
19
|
+
generate_pages_from_generated_nodes(site, layout, children, next_url)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class GeneratedPage < ::Jekyll::Page
|
25
|
+
def initialize(site, layout, nav, parent_url)
|
26
|
+
@site = site
|
27
|
+
@name = 'index.html'
|
28
|
+
|
29
|
+
process(@name)
|
30
|
+
@data = {}
|
31
|
+
data['title'] = nav['text']
|
32
|
+
data['permalink'] = parent_url + nav['url']
|
33
|
+
data['layout'] = layout
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative './breadcrumbs'
|
2
|
+
require_relative './generated_pages'
|
3
|
+
require_relative './namespace_flattener'
|
4
|
+
|
5
|
+
require 'jekyll'
|
6
|
+
|
7
|
+
module JekyllThemeGuidesMbland
|
8
|
+
class Generator < ::Jekyll::Generator
|
9
|
+
def generate(site)
|
10
|
+
GeneratedPages.generate_pages_from_navigation_data(site)
|
11
|
+
pages = site.collections['pages']
|
12
|
+
docs = (pages.nil? ? [] : pages.docs) + site.pages
|
13
|
+
Breadcrumbs.generate(site, docs)
|
14
|
+
NamespaceFlattener.flatten_url_namespace(site, docs)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module JekyllThemeGuidesMbland
|
2
|
+
class NamespaceFlattener
|
3
|
+
def self.flatten_url_namespace(site, docs)
|
4
|
+
flatten_urls(docs) if site.config['flat_namespace']
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.flatten_urls(docs)
|
8
|
+
flat_to_orig = {}
|
9
|
+
docs.each { |page| flatten_page_urls(page, flat_to_orig) }
|
10
|
+
check_for_collisions(flat_to_orig)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.flatten_page_urls(page, flat_to_orig)
|
14
|
+
orig_url = page.permalink || page.url
|
15
|
+
flattened_url = flat_url(orig_url)
|
16
|
+
(flat_to_orig[flattened_url] ||= []) << orig_url
|
17
|
+
page.data['permalink'] = flattened_url
|
18
|
+
(page.data['breadcrumbs'] || []).each do |crumb|
|
19
|
+
crumb['url'] = flat_url(crumb['url'])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.flat_url(url)
|
24
|
+
url == '/' ? url : "/#{url.split('/')[1..-1].last}/"
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.check_for_collisions(flat_to_orig)
|
28
|
+
collisions = flat_to_orig.map do |flattened, orig|
|
29
|
+
[flattened, orig] if orig.size != 1
|
30
|
+
end.compact
|
31
|
+
|
32
|
+
return if collisions.empty?
|
33
|
+
|
34
|
+
messages = collisions.map { |flat, orig| "#{flat}: #{orig.join(', ')}" }
|
35
|
+
raise StandardError, "collisions in flattened namespace between\n " +
|
36
|
+
messages.join("\n ")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,257 @@
|
|
1
|
+
require_relative './generated_nodes'
|
2
|
+
|
3
|
+
require 'jekyll'
|
4
|
+
require 'safe_yaml'
|
5
|
+
|
6
|
+
module JekyllThemeGuidesMbland
|
7
|
+
module FrontMatter
|
8
|
+
EXTNAMES = %w[.md .html].freeze
|
9
|
+
|
10
|
+
def self.load(basedir)
|
11
|
+
# init_file_to_front_matter_map is initializing the map with a nil value
|
12
|
+
# for every file that _should_ contain front matter as far as the
|
13
|
+
# navigation menu is concerned. Any nil values that remain after merging
|
14
|
+
# with the site_file_to_front_matter map will result in a validation
|
15
|
+
# error.
|
16
|
+
init_file_to_front_matter_map(basedir)
|
17
|
+
.merge(site_file_to_front_matter(init_site(basedir)))
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.validate_with_message_upon_error(front_matter)
|
21
|
+
files_with_errors = validate front_matter
|
22
|
+
return if files_with_errors.empty?
|
23
|
+
message = ['The following files have errors in their front matter:']
|
24
|
+
files_with_errors.each do |file, errors|
|
25
|
+
message << " #{file}:"
|
26
|
+
message.concat(errors.map { |error| " #{error}" })
|
27
|
+
end
|
28
|
+
message.join "\n" unless message.size == 1
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.validate(front_matter)
|
32
|
+
front_matter.map do |file, data|
|
33
|
+
next [file, ['no front matter defined']] if data.nil?
|
34
|
+
errors = missing_property_errors(data) + permalink_errors(data)
|
35
|
+
[file, errors] unless errors.empty?
|
36
|
+
end.compact.to_h
|
37
|
+
end
|
38
|
+
|
39
|
+
class << self
|
40
|
+
private
|
41
|
+
|
42
|
+
def init_site(basedir)
|
43
|
+
Dir.chdir(basedir) do
|
44
|
+
config = SafeYAML.load_file('_config.yml', safe: true)
|
45
|
+
adjust_config_paths(basedir, config)
|
46
|
+
site = Jekyll::Site.new(Jekyll.configuration(config))
|
47
|
+
site.reset
|
48
|
+
site.read
|
49
|
+
site
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def adjust_config_paths(basedir, config)
|
54
|
+
source = config['source']
|
55
|
+
config['source'] = source.nil? ? basedir : File.join(basedir, source)
|
56
|
+
destination = config['destination']
|
57
|
+
destination = '_site' if destination.nil?
|
58
|
+
config['destination'] = File.join(basedir, destination)
|
59
|
+
end
|
60
|
+
|
61
|
+
def site_file_to_front_matter(site)
|
62
|
+
site_pages(site).map do |page|
|
63
|
+
[page.relative_path, page.data]
|
64
|
+
end.to_h
|
65
|
+
end
|
66
|
+
|
67
|
+
# We're supporting two possible configurations:
|
68
|
+
#
|
69
|
+
# - a `pages/` directory in which documents appear as part of the regular
|
70
|
+
# site.pages collection; we have to filter by page.relative_path, and we
|
71
|
+
# do not assign a permalink so that validation (in a later step) will
|
72
|
+
# ensure that each page has a permalink assigned
|
73
|
+
#
|
74
|
+
# - an actual `pages` collection, stored in a `_pages` directory; no
|
75
|
+
# filtering is necessary, and we can reliably set the permalink to
|
76
|
+
# page.url as a default
|
77
|
+
def site_pages(site)
|
78
|
+
pages = site.collections['pages']
|
79
|
+
if pages.nil?
|
80
|
+
site.pages.select do |page|
|
81
|
+
# Handle both with and without leading slash, as leading slash was
|
82
|
+
# removed in v3.2.0.pre.beta2:
|
83
|
+
# jekyll/jekyll/commit/4fbbeddae20fa52732f30ef001bb1f80258bc5d7
|
84
|
+
page.relative_path.start_with?('/pages/', 'pages/') ||
|
85
|
+
page.url == '/'
|
86
|
+
end
|
87
|
+
else
|
88
|
+
pages.docs.each { |page| page.data['permalink'] ||= page.url }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def init_file_to_front_matter_map(basedir)
|
93
|
+
file_to_front_matter = {}
|
94
|
+
Dir.chdir(basedir) do
|
95
|
+
pages_dir = Dir.exist?('_pages') ? '_pages' : 'pages'
|
96
|
+
Dir[File.join(pages_dir, '**', '*')].each do |file_name|
|
97
|
+
extname = File.extname(file_name)
|
98
|
+
next unless File.file?(file_name) && EXTNAMES.include?(extname)
|
99
|
+
file_to_front_matter[file_name] = nil
|
100
|
+
end
|
101
|
+
end
|
102
|
+
file_to_front_matter
|
103
|
+
end
|
104
|
+
|
105
|
+
def missing_property_errors(data)
|
106
|
+
properties = %w[title permalink]
|
107
|
+
properties.map { |p| "no `#{p}:` property" if data[p].nil? }.compact
|
108
|
+
end
|
109
|
+
|
110
|
+
def permalink_errors(data)
|
111
|
+
pl = data['permalink']
|
112
|
+
return [] if pl.nil?
|
113
|
+
errors = []
|
114
|
+
errors << "`permalink:` does not begin with '/'" \
|
115
|
+
unless pl.start_with? '/'
|
116
|
+
errors << "`permalink:` does not end with '/'" unless pl.end_with? '/'
|
117
|
+
errors
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Automatically updates the `navigation:` field in _config.yml.
|
123
|
+
#
|
124
|
+
# Does this by parsing the front matter from files in `pages/`. Preserves the
|
125
|
+
# existing order of items in `navigation:`, but new items may need to be
|
126
|
+
# reordered manually.
|
127
|
+
def self.update_navigation_configuration(basedir)
|
128
|
+
config_path = File.join basedir, '_config.yml'
|
129
|
+
config_data = SafeYAML.load_file config_path, safe: true
|
130
|
+
return unless config_data
|
131
|
+
nav_data = config_data['navigation'] || []
|
132
|
+
NavigationMenu.update_navigation_data(nav_data, basedir, config_data)
|
133
|
+
NavigationMenuWriter.write_navigation_data_to_config_file(config_path,
|
134
|
+
nav_data)
|
135
|
+
end
|
136
|
+
|
137
|
+
module NavigationMenu
|
138
|
+
def self.update_navigation_data(nav_data, basedir, config_data)
|
139
|
+
original = map_nav_items_by_url('/', nav_data).to_h
|
140
|
+
updated = updated_nav_data(basedir)
|
141
|
+
remove_stale_nav_entries(nav_data, original, updated)
|
142
|
+
updated.map { |url, nav| apply_nav_update(url, nav, nav_data, original) }
|
143
|
+
if config_data['generate_nodes']
|
144
|
+
GeneratedNodes.create_homes_for_orphans(original, nav_data)
|
145
|
+
else
|
146
|
+
check_for_orphaned_items(nav_data)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.map_nav_items_by_url(parent_url, nav_data)
|
151
|
+
nav_data.flat_map do |nav|
|
152
|
+
url = File.join('', parent_url, nav['url'] || '')
|
153
|
+
[[url, nav]].concat(map_nav_items_by_url(url, nav['children'] || []))
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def self.updated_nav_data(basedir)
|
158
|
+
front_matter = FrontMatter.load basedir
|
159
|
+
errors = FrontMatter.validate_with_message_upon_error front_matter
|
160
|
+
abort errors + "\n_config.yml not updated" if errors
|
161
|
+
front_matter
|
162
|
+
.values.sort_by { |fm| fm['permalink'] }
|
163
|
+
.map { |fm| [fm['permalink'], page_nav(fm)] }.to_h
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.page_nav(front_matter)
|
167
|
+
url_components = front_matter['permalink'].split('/')[1..-1]
|
168
|
+
result = {
|
169
|
+
'text' => front_matter['navtitle'] || front_matter['title'],
|
170
|
+
'url' => "#{url_components.nil? ? '' : url_components.last}/",
|
171
|
+
'internal' => true,
|
172
|
+
}
|
173
|
+
# Delete the root URL so we don't have an empty `url:` property laying
|
174
|
+
# around.
|
175
|
+
result.delete 'url' if result['url'] == '/'
|
176
|
+
result
|
177
|
+
end
|
178
|
+
|
179
|
+
def self.remove_stale_nav_entries(nav_data, original, updated)
|
180
|
+
# Remove old entries whose pages have been deleted
|
181
|
+
original.each do |url, nav|
|
182
|
+
if !updated.member?(url) && nav['internal'] && !nav['generated']
|
183
|
+
nav['delete'] = true
|
184
|
+
end
|
185
|
+
end
|
186
|
+
original.delete_if { |_url, nav| nav['delete'] }
|
187
|
+
nav_data.delete_if { |nav| nav['delete'] }
|
188
|
+
nav_data.each { |nav| remove_stale_children(nav) }
|
189
|
+
end
|
190
|
+
|
191
|
+
def self.remove_stale_children(parent)
|
192
|
+
children = (parent['children'] || [])
|
193
|
+
children.delete_if { |nav| nav['delete'] }
|
194
|
+
parent.delete 'children' if children.empty?
|
195
|
+
children.each { |child| remove_stale_children(child) }
|
196
|
+
end
|
197
|
+
|
198
|
+
def self.apply_nav_update(url, nav, nav_data, original)
|
199
|
+
orig = original[url]
|
200
|
+
if orig.nil?
|
201
|
+
apply_new_nav_item(url, nav, nav_data, original)
|
202
|
+
else
|
203
|
+
orig['text'] = nav['text']
|
204
|
+
orig.delete('generated')
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def self.apply_new_nav_item(url, nav, nav_data, original)
|
209
|
+
parent_url = File.dirname(url || '/')
|
210
|
+
parent = original["#{parent_url}/"]
|
211
|
+
if parent_url == '/'
|
212
|
+
nav_data << (original[url] = nav)
|
213
|
+
elsif parent.nil?
|
214
|
+
nav_data << nav.merge(orphan_url: url)
|
215
|
+
else
|
216
|
+
(parent['children'] ||= []) << nav
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def self.check_for_orphaned_items(nav_data)
|
221
|
+
orphan_urls = nav_data.map { |nav| nav[:orphan_url] }.compact
|
222
|
+
return if orphan_urls.empty?
|
223
|
+
raise StandardError, "Parent pages missing for the following:\n " +
|
224
|
+
orphan_urls.join("\n ")
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
class NavigationMenuWriter
|
229
|
+
def self.write_navigation_data_to_config_file(config_path, nav_data)
|
230
|
+
lines = []
|
231
|
+
in_navigation = false
|
232
|
+
open(config_path).each_line do |line|
|
233
|
+
in_navigation = process_line line, lines, nav_data, in_navigation
|
234
|
+
end
|
235
|
+
File.write config_path, lines.join
|
236
|
+
end
|
237
|
+
|
238
|
+
def self.process_line(line, lines, nav_data, in_navigation = false)
|
239
|
+
if !in_navigation && line.start_with?('navigation:')
|
240
|
+
lines << line << format_navigation_section(nav_data)
|
241
|
+
in_navigation = true
|
242
|
+
elsif in_navigation
|
243
|
+
in_navigation = line.start_with?(' ', '-')
|
244
|
+
lines << line unless in_navigation
|
245
|
+
else
|
246
|
+
lines << line
|
247
|
+
end
|
248
|
+
in_navigation
|
249
|
+
end
|
250
|
+
|
251
|
+
YAML_PREFIX = "---\n".freeze
|
252
|
+
|
253
|
+
def self.format_navigation_section(nav_data)
|
254
|
+
nav_data.empty? ? '' : nav_data.to_yaml[YAML_PREFIX.size..-1]
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'English'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module JekyllThemeGuidesMbland
|
5
|
+
TEMPLATE_FILES = %w[
|
6
|
+
_pages/add-a-new-page/make-a-child-page.md
|
7
|
+
_pages/add-a-new-page.md
|
8
|
+
_pages/add-images.md
|
9
|
+
_pages/advanced-features.md
|
10
|
+
_pages/github-setup.md
|
11
|
+
_pages/images.png
|
12
|
+
_pages/post-your-guide.md
|
13
|
+
_pages/update-the-config-file/understanding-baseurl.md
|
14
|
+
_pages/update-the-config-file.md
|
15
|
+
images/description.png
|
16
|
+
images/gh-add-guide.png
|
17
|
+
images/gh-branches-link.png
|
18
|
+
images/gh-default-branch.png
|
19
|
+
images/gh-settings-button.png
|
20
|
+
images/gh-webhook.png
|
21
|
+
].freeze
|
22
|
+
|
23
|
+
def self.clear_template_files_and_create_new_repository(basedir,
|
24
|
+
outstream = $stdout)
|
25
|
+
remove_template_files basedir, outstream
|
26
|
+
delete_create_repo_command_from_go_script basedir, outstream
|
27
|
+
create_new_git_repository basedir, outstream
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.remove_template_files(basedir, outstream)
|
31
|
+
Dir.chdir basedir do
|
32
|
+
outstream.puts 'Clearing Guides Template files.'
|
33
|
+
files = TEMPLATE_FILES.map { |f| File.join basedir, f }
|
34
|
+
.select { |f| File.exist? f }
|
35
|
+
File.delete(*files)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.delete_create_repo_command_from_go_script(basedir, outstream)
|
40
|
+
Dir.chdir basedir do
|
41
|
+
outstream.puts 'Removing `:create_repo` command from the `./go` script.'
|
42
|
+
go_script = File.join basedir, 'go'
|
43
|
+
content = File.read go_script
|
44
|
+
match = /\ndef_command\(\n :create_repo,.*?end\n/m.match content
|
45
|
+
content = "#{match.pre_match}#{match.post_match}" unless match.nil?
|
46
|
+
File.write go_script, content
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
GIT_COMMANDS = {
|
51
|
+
'Creating a new git repository.' => 'git init',
|
52
|
+
'Creating mbland-pages branch.' => 'git checkout -b mbland-pages',
|
53
|
+
'Adding files for initial commit.' => 'git add .',
|
54
|
+
}.freeze
|
55
|
+
|
56
|
+
def self.create_new_git_repository(basedir, outstream)
|
57
|
+
Dir.chdir basedir do
|
58
|
+
outstream.puts 'Removing old git repository.'
|
59
|
+
FileUtils.rm_rf '.git'
|
60
|
+
GIT_COMMANDS.each do |description, command|
|
61
|
+
outstream.puts description
|
62
|
+
exec_cmd_capture_output command, outstream
|
63
|
+
end
|
64
|
+
outstream.puts "All done! Run \'git commit\' to create your first commit."
|
65
|
+
end
|
66
|
+
end
|
67
|
+
private_class_method :create_new_git_repository
|
68
|
+
|
69
|
+
def self.exec_cmd_capture_output(command, outstream)
|
70
|
+
opts = { out: outstream, err: outstream }
|
71
|
+
exit $CHILD_STATUS.exitstatus unless system command, opts
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'jekyll/tags/include'
|
2
|
+
require 'liquid'
|
3
|
+
|
4
|
+
module JekyllThemeGuidesMbland
|
5
|
+
class ShouldExpandNavTag < ::Liquid::Tag
|
6
|
+
NAME = 'jekyll_theme_guides_mbland_should_expand_nav'.freeze
|
7
|
+
::Liquid::Template.register_tag(NAME, self)
|
8
|
+
|
9
|
+
attr_reader :parent_reference, :url_reference
|
10
|
+
|
11
|
+
def initialize(_tag_name, markup, _)
|
12
|
+
references = markup.split(',').map(&:strip)
|
13
|
+
@parent_reference = references.shift
|
14
|
+
@url_reference = references.shift
|
15
|
+
end
|
16
|
+
|
17
|
+
def render(context)
|
18
|
+
scope = context.scopes.detect { |s| s.member?(url_reference) }
|
19
|
+
parent_url = scope[url_reference]
|
20
|
+
page_url = context['page']['url']
|
21
|
+
page_url == parent_url || page_url.start_with?(parent_url) ||
|
22
|
+
expand_nav_default(scope, context)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def expand_nav_default(scope, context)
|
28
|
+
default = scope[parent_reference]['expand_nav']
|
29
|
+
default = context['site']['expand_nav'] if default.nil?
|
30
|
+
default.nil? ? false : default
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class PopLastUrlComponent < ::Liquid::Tag
|
35
|
+
NAME = 'jekyll_theme_guides_mbland_pop_last_url_component'.freeze
|
36
|
+
::Liquid::Template.register_tag(NAME, self)
|
37
|
+
|
38
|
+
attr_reader :reference
|
39
|
+
|
40
|
+
def initialize(_tag_name, markup, _)
|
41
|
+
@reference = markup.strip
|
42
|
+
end
|
43
|
+
|
44
|
+
def render(context)
|
45
|
+
scope = context.scopes.detect { |s| s.member?(reference) }
|
46
|
+
parent_url = scope[reference]
|
47
|
+
result = File.dirname(parent_url)
|
48
|
+
result == '/' ? result : "#{result}/"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jekyll-theme-guides-mbland
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Bland
|
@@ -180,6 +180,17 @@ files:
|
|
180
180
|
- assets/js/guide.js
|
181
181
|
- assets/js/vendor/anchor.min.js
|
182
182
|
- assets/js/vendor/jquery-1.11.2.min.js
|
183
|
+
- lib/jekyll-theme-guides-mbland.rb
|
184
|
+
- lib/jekyll-theme-guides-mbland/breadcrumbs.rb
|
185
|
+
- lib/jekyll-theme-guides-mbland/generated_nodes.rb
|
186
|
+
- lib/jekyll-theme-guides-mbland/generated_pages.rb
|
187
|
+
- lib/jekyll-theme-guides-mbland/generator.rb
|
188
|
+
- lib/jekyll-theme-guides-mbland/namespace_flattener.rb
|
189
|
+
- lib/jekyll-theme-guides-mbland/navigation.rb
|
190
|
+
- lib/jekyll-theme-guides-mbland/repository.rb
|
191
|
+
- lib/jekyll-theme-guides-mbland/tags.rb
|
192
|
+
- lib/jekyll-theme-guides-mbland/update.rb
|
193
|
+
- lib/jekyll-theme-guides-mbland/version.rb
|
183
194
|
homepage: https://github.com/mbland/jekyll-theme-guides-mbland
|
184
195
|
licenses:
|
185
196
|
- ISC
|