swedbank-pay-design-guide-jekyll-theme 1.8.1 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/_plugins/sidebar.rb +2 -1
- data/lib/gem_version.rb +1 -1
- data/lib/safe_merge.rb +28 -0
- data/lib/sanitized_filename.rb +12 -0
- data/lib/sidebar.rb +24 -189
- data/lib/sidebar_html_builder.rb +141 -0
- data/lib/sidebar_page.rb +117 -0
- data/lib/sidebar_page_collection.rb +37 -0
- data/lib/sidebar_page_title.rb +29 -0
- data/lib/sidebar_parser.rb +62 -0
- data/lib/sidebar_path.rb +62 -0
- data/lib/sidebar_renderer.rb +51 -0
- data/lib/sidebar_text_builder.rb +46 -0
- data/lib/sidebar_tree_builder.rb +73 -0
- metadata +28 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4baacc614edb524f53a8b0a23788382fba5ec477f10f08888adf08fcbde24998
|
4
|
+
data.tar.gz: 0cb1ef91541ba25c94708789ab05379ea92fc94ea0a7a62c336182f108a62544
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0bf78e21de260346ee939876981e7cfeb2558e74a2d492217a07c4a23bde14018eb746225e7ad5f23420cacf89c2c82e07dc8c008a2ed588e7a5a9934ea2862f
|
7
|
+
data.tar.gz: bba4b0c952ee13e087c0e6f38c738d3999874e0670a3881e053b2b7fc58ae5e39ec748af3d64e3548c45efe79e9984539f193340ebaf73263e10ebddcdbe74e4
|
data/_plugins/sidebar.rb
CHANGED
data/lib/gem_version.rb
CHANGED
data/lib/safe_merge.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The Hash class
|
4
|
+
class Hash
|
5
|
+
# Safely merges the current Hash with an 'other' Hash.
|
6
|
+
def safe_merge(other)
|
7
|
+
all_keys = keys | other.keys
|
8
|
+
result_hash = {}
|
9
|
+
|
10
|
+
all_keys.each do |key|
|
11
|
+
hash_value = {}
|
12
|
+
|
13
|
+
if key? key
|
14
|
+
value = self[key]
|
15
|
+
hash_value = value unless value.nil?
|
16
|
+
end
|
17
|
+
|
18
|
+
if other.key? key
|
19
|
+
value = other[key]
|
20
|
+
hash_value = hash_value.merge(value) unless value.nil?
|
21
|
+
end
|
22
|
+
|
23
|
+
result_hash[key] = hash_value
|
24
|
+
end
|
25
|
+
|
26
|
+
result_hash
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The String class
|
4
|
+
class String
|
5
|
+
# Sanitizes a filename
|
6
|
+
def sanitized
|
7
|
+
match = match(/(?m)(?<=\b_site).*$/)
|
8
|
+
sanitized_filename = match ? match[0] : self
|
9
|
+
sanitized_filename = sanitized_filename.gsub('index.html', '')
|
10
|
+
sanitized_filename.gsub('.html', '')
|
11
|
+
end
|
12
|
+
end
|
data/lib/sidebar.rb
CHANGED
@@ -3,211 +3,46 @@
|
|
3
3
|
require 'jekyll'
|
4
4
|
require 'nokogiri'
|
5
5
|
require 'json'
|
6
|
+
require_relative 'sidebar_page'
|
7
|
+
require_relative 'sidebar_parser'
|
8
|
+
require_relative 'sidebar_renderer'
|
9
|
+
require_relative 'sidebar_tree_builder'
|
6
10
|
|
7
|
-
module
|
11
|
+
module SwedbankPay
|
8
12
|
# A nice sidebar
|
9
|
-
|
10
|
-
|
11
|
-
|
13
|
+
module Sidebar
|
14
|
+
class << self
|
15
|
+
attr_reader :pages
|
12
16
|
|
13
|
-
|
14
|
-
|
15
|
-
@filename_with_headers = {}
|
16
|
-
end
|
17
|
-
|
18
|
-
def pre_render(page)
|
19
|
-
menu_order = page['menu_order'].nil? ? 0 : page['menu_order']
|
20
|
-
hide_from_sidebar = page['hide_from_sidebar'].nil? ? false : page['hide_from_sidebar']
|
21
|
-
url = page['url'].gsub('index.html', '').gsub('.html', '')
|
22
|
-
@hash_pre_render[url] = {
|
23
|
-
title: page['title'],
|
24
|
-
url: page['url'].gsub('.html', ''),
|
25
|
-
name: page['name'],
|
26
|
-
menu_order: menu_order,
|
27
|
-
hide_from_sidebar: hide_from_sidebar
|
28
|
-
}
|
29
|
-
end
|
30
|
-
|
31
|
-
def post_write(site)
|
32
|
-
files = []
|
33
|
-
Dir.glob("#{site.config['destination']}/**/*.html") do |filename|
|
34
|
-
doc = File.open(filename) { |f| Nokogiri::HTML(f) }
|
35
|
-
files.push(doc)
|
36
|
-
|
37
|
-
headers = []
|
38
|
-
doc.xpath('//h2 ').each do |header|
|
39
|
-
next unless header['id']
|
40
|
-
|
41
|
-
child = header.last_element_child
|
42
|
-
header = {
|
43
|
-
id: header['id'],
|
44
|
-
title: header.content.strip,
|
45
|
-
hash: (child['href']).to_s
|
46
|
-
}
|
47
|
-
headers.push(header)
|
48
|
-
end
|
49
|
-
sanitized_filename = sanitize_filename(filename)
|
50
|
-
@filename_with_headers[sanitized_filename] = { headers: headers }
|
51
|
-
end
|
52
|
-
|
53
|
-
Dir.glob("#{site.config['destination']}/**/*.html") do |filename|
|
54
|
-
sanitized_filename = sanitize_filename(filename)
|
55
|
-
sidebar = render(sanitized_filename)
|
56
|
-
file = File.open(filename) { |f| Nokogiri::HTML(f) }
|
57
|
-
file.xpath('//*[@id="dx-sidebar-main-nav-ul"]').each do |location|
|
58
|
-
location.inner_html = sidebar
|
59
|
-
end
|
60
|
-
File.open(filename, 'w') { |f| f.write(file.to_html(encoding: 'UTF-8')) }
|
61
|
-
end
|
62
|
-
|
63
|
-
# File.open('_site/sidebar.html', 'w') { |f| f.write(sidebar) }
|
64
|
-
end
|
65
|
-
|
66
|
-
private
|
67
|
-
|
68
|
-
def sanitize_filename(filename)
|
69
|
-
sanitized_filename = filename.match(/(?m)(?<=\b_site).*$/)[0]
|
70
|
-
sanitized_filename = sanitized_filename.gsub('index.html', '')
|
71
|
-
sanitized_filename.gsub('.html', '')
|
72
|
-
end
|
73
|
-
|
74
|
-
def generateSubgroup(filename, key, value, all_subgroups, level)
|
75
|
-
title = value[:title].split('–').last
|
76
|
-
|
77
|
-
subsubgroup_list = all_subgroups.select do |subsubgroup_key, _subsubgroup_value|
|
78
|
-
subsubgroup_key.include? key and subsubgroup_key != key and \
|
79
|
-
key.split('/').length > level
|
80
|
-
end
|
81
|
-
|
82
|
-
subgroup = ''
|
83
|
-
has_subgroups = !all_subgroups.empty?
|
84
|
-
if value[:headers].any? || !subsubgroup_list.empty?
|
85
|
-
if has_subgroups
|
86
|
-
url = value[:url]
|
87
|
-
active = active?(filename, url, true)
|
88
|
-
# puts "#{url}, #{filename}, #{key}" if active
|
89
|
-
item_class = active || (url.split('/').length > level && filename.start_with?(url)) ? 'nav-subgroup active' : 'nav-subgroup'
|
90
|
-
subgroup << "<li class=\"#{item_class}\">"
|
91
|
-
subgroup << "<div class=\"nav-subgroup-heading\"><i class=\"material-icons\">arrow_right</i><a href=\"#{url}\">#{title}</a></div>"
|
92
|
-
subgroup << '<ul class="nav-ul">'
|
93
|
-
|
94
|
-
if subsubgroup_list.empty?
|
95
|
-
value[:headers].each do |header|
|
96
|
-
subgroup << "<li class=\"nav-leaf\"><a href=\"#{value[:url]}#{header[:hash]}\">#{header[:title]}</a></li>"
|
97
|
-
end
|
98
|
-
else
|
99
|
-
subgroup_leaf_class = active ? 'nav-leaf nav-subgroup-leaf active' : 'nav-leaf nav-subgroup-leaf'
|
100
|
-
subgroup << "<li class=\"#{subgroup_leaf_class}\"><a href=\"#{value[:url]}\">#{title} overview</a></li>"
|
101
|
-
|
102
|
-
subsubgroup_list.each do |subsubgroup_key, subsubgroup_value|
|
103
|
-
subgroup << generateSubgroup(filename, subsubgroup_key, subsubgroup_value, subsubgroup_list, 3)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
subgroup << '</ul>'
|
108
|
-
subgroup << '</li>'
|
109
|
-
else
|
110
|
-
value[:headers].each do |header|
|
111
|
-
subgroup << "<li class=\"nav-leaf\"><a href=\"#{value[:url]}#{header[:hash]}\">#{header[:title]}</a></li>"
|
112
|
-
end
|
113
|
-
end
|
114
|
-
else
|
115
|
-
subgroup << if has_subgroups
|
116
|
-
"<li class=\"nav-leaf nav-subgroup-leaf\"><a href=\"#{value[:url]}\">#{title}</a></li>"
|
117
|
-
else
|
118
|
-
"<li class=\"nav-leaf\"><a href=\"#{value[:url]}\">#{title}</a></li>"
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
subgroup
|
123
|
-
end
|
124
|
-
|
125
|
-
def render(filename)
|
126
|
-
sidebar = ''
|
127
|
-
|
128
|
-
merged = merge(@hash_pre_render, @filename_with_headers).sort_by { |_key, value| value[:menu_order] }
|
129
|
-
merged.select { |key, _value| key.split('/').length <= 2 }.each do |key, value|
|
130
|
-
next if value[:title].nil?
|
131
|
-
next if value[:hide_from_sidebar]
|
132
|
-
|
133
|
-
subgroups = merged.select { |subgroup_key, _subgroup_value| subgroup_key.include? key and subgroup_key != key and key != '/' }
|
134
|
-
|
135
|
-
active = active?(filename, key)
|
136
|
-
# puts "#{filename}, #{key}" if active
|
137
|
-
item_class = active ? 'nav-group active' : 'nav-group'
|
138
|
-
|
139
|
-
child = "<li class=\"#{item_class}\">"
|
140
|
-
child << "<div class=\"nav-group-heading\"><i class=\"material-icons\">arrow_right</i><span>#{value[:title].split('–').first}</span></div>"
|
141
|
-
|
142
|
-
child << '<ul class="nav-ul">'
|
143
|
-
|
144
|
-
subgroup = generateSubgroup(filename, key, value, subgroups, 2)
|
145
|
-
|
146
|
-
child << subgroup
|
147
|
-
|
148
|
-
if subgroups.any?
|
149
|
-
subgroups.select { |subgroup_key, _subgroup_value| subgroup_key.split('/').length <= 3 }.each do |subgroup_key, subgroup_value|
|
150
|
-
subgroup = generateSubgroup(filename, subgroup_key, subgroup_value, subgroups, 2)
|
151
|
-
child << subgroup
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
child << '</ul>'
|
156
|
-
child << '</li>'
|
157
|
-
sidebar << child
|
17
|
+
def init
|
18
|
+
@pages_hash = {}
|
158
19
|
end
|
159
20
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
def active?(filename, url, exact = false)
|
165
|
-
if filename == '/' || url == '/'
|
166
|
-
if filename == '/' && url == '/'
|
167
|
-
return true
|
168
|
-
else
|
169
|
-
return false
|
170
|
-
end
|
21
|
+
def pre_render(jekyll_page)
|
22
|
+
sidebar_page = SidebarPage.new(jekyll_page)
|
23
|
+
@pages_hash[sidebar_page.path] = sidebar_page
|
171
24
|
end
|
172
25
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
all_keys.each do |key|
|
181
|
-
hash_value = {}
|
182
|
-
|
183
|
-
if hash1.key? key
|
184
|
-
value = hash1[key]
|
185
|
-
|
186
|
-
hash_value = value unless value.nil?
|
187
|
-
end
|
188
|
-
|
189
|
-
if hash2.key? key
|
190
|
-
value = hash2[key]
|
191
|
-
|
192
|
-
hash_value = hash_value.merge(value) unless value.nil?
|
193
|
-
end
|
194
|
-
|
195
|
-
result_hash[key] = hash_value
|
26
|
+
def post_write(site)
|
27
|
+
parser = SidebarParser.new(site)
|
28
|
+
pages = parser.parse(@pages_hash)
|
29
|
+
@pages = SidebarTreeBuilder.new(pages)
|
30
|
+
Jekyll.logger.debug(" Sidebar: #{@pages.inspect}")
|
31
|
+
renderer = SidebarRenderer.new
|
32
|
+
renderer.render(@pages)
|
196
33
|
end
|
197
|
-
|
198
|
-
result_hash
|
199
34
|
end
|
200
35
|
end
|
201
36
|
end
|
202
37
|
|
203
|
-
|
38
|
+
SwedbankPay::Sidebar.init
|
204
39
|
|
205
|
-
Jekyll::Hooks.register :site, :pre_render do |site,
|
40
|
+
Jekyll::Hooks.register :site, :pre_render do |site, _|
|
206
41
|
site.pages.each do |page|
|
207
|
-
|
42
|
+
SwedbankPay::Sidebar.pre_render page
|
208
43
|
end
|
209
44
|
end
|
210
45
|
|
211
46
|
Jekyll::Hooks.register :site, :post_write do |site|
|
212
|
-
|
47
|
+
SwedbankPay::Sidebar.post_write site
|
213
48
|
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require_relative 'sidebar_page'
|
4
|
+
|
5
|
+
module SwedbankPay
|
6
|
+
# The builder of HTML for the Sidebar
|
7
|
+
class SidebarHTMLBuilder
|
8
|
+
def initialize(tree)
|
9
|
+
@tree = tree
|
10
|
+
end
|
11
|
+
|
12
|
+
def build(current_page)
|
13
|
+
raise ArgumentError, 'current_page cannot be nil' if current_page.nil?
|
14
|
+
raise ArgumentError, "#{current_page.class} is not a #{SidebarPage}" unless current_page.is_a? SidebarPage
|
15
|
+
|
16
|
+
build_markup(@tree, current_page)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def build_markup(pages, current_page)
|
22
|
+
return '' if pages.empty?
|
23
|
+
|
24
|
+
current_path = current_path(current_page)
|
25
|
+
markup = ''
|
26
|
+
|
27
|
+
pages.each do |page|
|
28
|
+
next if page.ignore?
|
29
|
+
|
30
|
+
sub_items_markup = sub_items_markup(page, current_path)
|
31
|
+
markup << item_markup(page, current_path, page.level, sub_items_markup)
|
32
|
+
end
|
33
|
+
|
34
|
+
markup
|
35
|
+
end
|
36
|
+
|
37
|
+
def current_path(current_page)
|
38
|
+
if current_page.nil?
|
39
|
+
Jekyll.logger.warn(' Sidebar: Nil current_page')
|
40
|
+
return ''
|
41
|
+
end
|
42
|
+
|
43
|
+
return current_page if current_page.is_a? String
|
44
|
+
return current_page.path if current_page.respond_to?(:path)
|
45
|
+
|
46
|
+
Jekyll.logger.warn(" Sidebar: #{current_page.class} ('#{current_page}') does not respond to :path.")
|
47
|
+
|
48
|
+
''
|
49
|
+
end
|
50
|
+
|
51
|
+
def item_markup(page, current_path, level, sub_items_markup)
|
52
|
+
title_markup = title_markup(page, level)
|
53
|
+
item_class = item_class(page, current_path, level)
|
54
|
+
group_heading_class = group_heading_class(level)
|
55
|
+
|
56
|
+
"<li class=\"#{item_class}\">
|
57
|
+
<div class=\"#{group_heading_class}\">
|
58
|
+
<i class=\"material-icons\">arrow_right</i>
|
59
|
+
#{title_markup}
|
60
|
+
</div>
|
61
|
+
#{sub_items_markup}
|
62
|
+
</li>"
|
63
|
+
end
|
64
|
+
|
65
|
+
def item_class(page, current_path, level)
|
66
|
+
active = active?(page, current_path, level)
|
67
|
+
item_class = group_class(level)
|
68
|
+
item_class += ' active' if active
|
69
|
+
item_class
|
70
|
+
end
|
71
|
+
|
72
|
+
def group_class(level)
|
73
|
+
level.zero? ? 'nav-group' : 'nav-subgroup'
|
74
|
+
end
|
75
|
+
|
76
|
+
def group_heading_class(level)
|
77
|
+
group_class = group_class(level)
|
78
|
+
"#{group_class}-heading"
|
79
|
+
end
|
80
|
+
|
81
|
+
def title_markup(page, level)
|
82
|
+
section_title = section_title(page)
|
83
|
+
return "<span>#{section_title}</span>" if level.zero?
|
84
|
+
|
85
|
+
item_title = item_title(page)
|
86
|
+
"<a href=\"#{page.path}\">#{item_title}</a>"
|
87
|
+
end
|
88
|
+
|
89
|
+
def sub_items_markup(page, current_path)
|
90
|
+
headers_markup = headers_markup(page, current_path)
|
91
|
+
child_markup = build_markup(page.children, current_path)
|
92
|
+
|
93
|
+
return '' if headers_markup.empty? && child_markup.empty?
|
94
|
+
|
95
|
+
"<ul class=\"nav-ul\">
|
96
|
+
#{headers_markup}
|
97
|
+
#{child_markup}
|
98
|
+
</ul>"
|
99
|
+
end
|
100
|
+
|
101
|
+
def headers_markup(page, current_path)
|
102
|
+
# If there's no page headers, only return a leaf item for the page itself.
|
103
|
+
return leaf_markup(page.path, page.title.item, page.level) unless page.headers?
|
104
|
+
|
105
|
+
# If there's no children, only return the headers as leaf node items.
|
106
|
+
return page.headers.map { |h| header_markup(page, h) }.join('') if page.children.empty?
|
107
|
+
|
108
|
+
headers_markup = page.headers.map { |h| header_markup(page, h) }.join('')
|
109
|
+
headers_markup = "<ul class=\"nav-ul\">#{headers_markup}</ul>"
|
110
|
+
|
111
|
+
item_markup(page, current_path, page.level + 1, headers_markup)
|
112
|
+
end
|
113
|
+
|
114
|
+
def header_markup(page, header)
|
115
|
+
hash = header[:hash]
|
116
|
+
subtitle = header[:title]
|
117
|
+
href = "#{page.path}#{hash}"
|
118
|
+
leaf_markup(href, subtitle)
|
119
|
+
end
|
120
|
+
|
121
|
+
def leaf_markup(href, title, level = 0)
|
122
|
+
leaf_class = level.positive? ? 'nav-leaf nav-subgroup-leaf' : 'nav-leaf'
|
123
|
+
"<li class=\"#{leaf_class}\"><a href=\"#{href}\">#{title}</a></li>"
|
124
|
+
end
|
125
|
+
|
126
|
+
def active?(page, current_path, level)
|
127
|
+
level.zero? ? page.active?(current_path) : page.path == current_path
|
128
|
+
end
|
129
|
+
|
130
|
+
def section_title(page)
|
131
|
+
return page.title.section unless page.title.section.nil?
|
132
|
+
return page.parent.title.to_s unless page.parent.nil? || page.parent.title.nil?
|
133
|
+
|
134
|
+
''
|
135
|
+
end
|
136
|
+
|
137
|
+
def item_title(page)
|
138
|
+
page.title.item
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
data/lib/sidebar_page.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require 'jekyll'
|
4
|
+
require_relative 'sidebar_path'
|
5
|
+
require_relative 'sidebar_page_title'
|
6
|
+
require_relative 'sidebar_page_collection'
|
7
|
+
require_relative 'sidebar_text_builder'
|
8
|
+
|
9
|
+
module SwedbankPay
|
10
|
+
# Represents a page in the Sidebar
|
11
|
+
class SidebarPage
|
12
|
+
FIXNUM_MAX = (2**(0.size * 8 - 2) - 1)
|
13
|
+
|
14
|
+
attr_reader :path, :title, :level, :order, :children, :name
|
15
|
+
attr_accessor :headers, :filename, :doc, :sidebar_container, :number, :parent
|
16
|
+
|
17
|
+
def initialize(page)
|
18
|
+
raise ArgumentError, 'Page must be a Jekyll::Page' unless page.is_a? Jekyll::Page
|
19
|
+
|
20
|
+
sidebar_path = SidebarPath.new(page['url'])
|
21
|
+
@path = sidebar_path.to_s
|
22
|
+
@parent = sidebar_path.parent
|
23
|
+
@level = sidebar_path.level
|
24
|
+
@name = sidebar_path.name
|
25
|
+
@hide_from_sidebar = page['hide_from_sidebar'].nil? ? false : page['hide_from_sidebar']
|
26
|
+
@title = page_title(page)
|
27
|
+
@order = menu_order(page)
|
28
|
+
@children = SidebarPageCollection.new(self)
|
29
|
+
end
|
30
|
+
|
31
|
+
def active?(current_path)
|
32
|
+
return true if @path == current_path
|
33
|
+
|
34
|
+
@children.each do |child|
|
35
|
+
return true if child.active?(current_path)
|
36
|
+
end
|
37
|
+
|
38
|
+
false
|
39
|
+
end
|
40
|
+
|
41
|
+
def ignore?
|
42
|
+
return true if @title.nil?
|
43
|
+
return true if @hide_from_sidebar
|
44
|
+
|
45
|
+
false
|
46
|
+
end
|
47
|
+
|
48
|
+
def children=(children)
|
49
|
+
@children = SidebarPageCollection.new(self, children)
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_s
|
53
|
+
SidebarTextBuilder.new(self).to_s
|
54
|
+
end
|
55
|
+
|
56
|
+
def inspect
|
57
|
+
to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
def <=>(other)
|
61
|
+
return -1 if other.nil?
|
62
|
+
|
63
|
+
if @order == FIXNUM_MAX && other.order == FIXNUM_MAX
|
64
|
+
return 0 if @title.nil? && other.title.nil?
|
65
|
+
return -1 if other.title.nil?
|
66
|
+
return 1 if title.nil?
|
67
|
+
|
68
|
+
return @title <=> other.title
|
69
|
+
end
|
70
|
+
|
71
|
+
@order <=> other.order
|
72
|
+
end
|
73
|
+
|
74
|
+
def save
|
75
|
+
Jekyll.logger.debug(" Writing Sidebar: #{filename}")
|
76
|
+
|
77
|
+
File.open(@filename, 'w') do |file|
|
78
|
+
html = @doc.to_html(encoding: 'UTF-8')
|
79
|
+
file.write(html)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def headers?
|
84
|
+
!headers.nil? && headers.any?
|
85
|
+
end
|
86
|
+
|
87
|
+
def coordinate
|
88
|
+
return @number.to_s if @parent.nil?
|
89
|
+
|
90
|
+
"#{@parent.coordinate}.#{@number}"
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def page_title(page)
|
96
|
+
title = page['title']
|
97
|
+
return nil if title.nil?
|
98
|
+
|
99
|
+
SidebarPageTitle.new(title)
|
100
|
+
end
|
101
|
+
|
102
|
+
def menu_order(page)
|
103
|
+
order = page['menu_order']
|
104
|
+
return FIXNUM_MAX if order.nil? || order.to_s.empty?
|
105
|
+
|
106
|
+
order.to_i
|
107
|
+
end
|
108
|
+
|
109
|
+
def eq?(path)
|
110
|
+
@path == path
|
111
|
+
end
|
112
|
+
|
113
|
+
def child_of?(path)
|
114
|
+
@path.split('/').length > @level && path.start_with?(@path)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module SwedbankPay
|
6
|
+
# Arranges Sidebar pages into a tree
|
7
|
+
class SidebarPageCollection
|
8
|
+
include Enumerable
|
9
|
+
extend Forwardable
|
10
|
+
def_delegators :@pages, :each, :length, :empty?, :[]
|
11
|
+
|
12
|
+
def initialize(parent, pages = [])
|
13
|
+
raise ArgumentError, 'Pages must be an array' unless pages.is_a? Array
|
14
|
+
|
15
|
+
@pages = []
|
16
|
+
|
17
|
+
pages.each_with_index do |page, index|
|
18
|
+
page.number = index
|
19
|
+
page.parent = parent
|
20
|
+
page.freeze
|
21
|
+
@pages.push(page)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def count
|
26
|
+
return 0 if @pages.empty?
|
27
|
+
|
28
|
+
count = @pages.length
|
29
|
+
|
30
|
+
@pages.each do |page|
|
31
|
+
count += page.children.count
|
32
|
+
end
|
33
|
+
|
34
|
+
count
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SwedbankPay
|
4
|
+
# Represents the title of a SidebarPage
|
5
|
+
class SidebarPageTitle
|
6
|
+
attr_reader :section, :item
|
7
|
+
|
8
|
+
def initialize(title)
|
9
|
+
@title = title
|
10
|
+
parts = title.split('–')
|
11
|
+
@section = parts.first.strip
|
12
|
+
@item = parts.last.strip
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
@title
|
17
|
+
end
|
18
|
+
|
19
|
+
def inspect
|
20
|
+
@title
|
21
|
+
end
|
22
|
+
|
23
|
+
def <=>(other)
|
24
|
+
return -1 if other.nil?
|
25
|
+
|
26
|
+
@title <=> other.to_s
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'sidebar_path'
|
4
|
+
|
5
|
+
module SwedbankPay
|
6
|
+
# The Sidebar renderer
|
7
|
+
class SidebarParser
|
8
|
+
def initialize(site)
|
9
|
+
@site = site
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse(pages)
|
13
|
+
destination = @site.config['destination']
|
14
|
+
|
15
|
+
Dir.glob("#{destination}/**/*.html") do |filename|
|
16
|
+
doc = File.open(filename) { |f| Nokogiri::HTML(f) }
|
17
|
+
path = SidebarPath.new(filename).to_s
|
18
|
+
page = pages[path]
|
19
|
+
|
20
|
+
raise ArgumentError, "No page found for '#{path}'." if page.nil?
|
21
|
+
|
22
|
+
page.doc = doc
|
23
|
+
page.filename = filename
|
24
|
+
page.headers = find_headers(doc)
|
25
|
+
page.sidebar_container = find_sidebar_container(filename, doc)
|
26
|
+
end
|
27
|
+
|
28
|
+
pages
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def find_headers(doc)
|
34
|
+
headers = []
|
35
|
+
|
36
|
+
doc.xpath('//h2').each do |header|
|
37
|
+
next unless header['id']
|
38
|
+
|
39
|
+
child_markup = header.last_element_child
|
40
|
+
header = {
|
41
|
+
id: header['id'],
|
42
|
+
title: header.content.strip,
|
43
|
+
hash: (child_markup['href']).to_s
|
44
|
+
}
|
45
|
+
headers.push(header)
|
46
|
+
end
|
47
|
+
|
48
|
+
headers
|
49
|
+
end
|
50
|
+
|
51
|
+
def find_sidebar_container(filename, doc)
|
52
|
+
sidebar_containers = doc.xpath('//*[@id="dx-sidebar-main-nav-ul"]')
|
53
|
+
|
54
|
+
unless sidebar_containers.any?
|
55
|
+
Jekyll.logger.debug(" Sidebar: No sidebar container found in #{filename}")
|
56
|
+
return nil
|
57
|
+
end
|
58
|
+
|
59
|
+
sidebar_containers.first
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/sidebar_path.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'sanitized_filename'
|
4
|
+
require_relative 'sidebar_page_title'
|
5
|
+
|
6
|
+
module SwedbankPay
|
7
|
+
# Represents a page in the Sidebar
|
8
|
+
class SidebarPath
|
9
|
+
attr_reader :parent, :level, :name
|
10
|
+
|
11
|
+
def initialize(path)
|
12
|
+
@segments = segment(path)
|
13
|
+
@path = normalized(path)
|
14
|
+
@name = construct_name
|
15
|
+
@parent = find_parent
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
@path
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def segment(path)
|
29
|
+
segments = path.sanitized.split('/').reject(&:empty?)
|
30
|
+
@level = segments.length.zero? ? 0 : segments.length - 1
|
31
|
+
segments
|
32
|
+
end
|
33
|
+
|
34
|
+
def normalized(path)
|
35
|
+
return '/' if @segments.empty?
|
36
|
+
|
37
|
+
joined = "/#{@segments.join('/')}"
|
38
|
+
|
39
|
+
# Directory paths should end with '/'.
|
40
|
+
directory?(path) ? "#{joined}/" : joined
|
41
|
+
end
|
42
|
+
|
43
|
+
def directory?(path)
|
44
|
+
path.end_with?('/') || path.end_with?('/index.html')
|
45
|
+
end
|
46
|
+
|
47
|
+
def construct_name
|
48
|
+
return '/' if @path == '/'
|
49
|
+
|
50
|
+
@segments.last
|
51
|
+
end
|
52
|
+
|
53
|
+
def find_parent
|
54
|
+
# If there's no or only one path segment, this is a root page
|
55
|
+
return nil if @segments.empty? || (@segments.length == 1)
|
56
|
+
|
57
|
+
# Return the path minus the last segment as the parent path
|
58
|
+
last = @path.sub(%r{(/#{@segments.last}/?)$}, '')
|
59
|
+
"#{last}/"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'sidebar_html_builder'
|
4
|
+
|
5
|
+
module SwedbankPay
|
6
|
+
# Renders the Sidebar
|
7
|
+
class SidebarRenderer
|
8
|
+
def render(tree)
|
9
|
+
raise ArgumentError, 'pages must be an SidebarTreeBuilder' unless tree.is_a? SidebarTreeBuilder
|
10
|
+
|
11
|
+
@tree = tree
|
12
|
+
render_pages(tree)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def render_pages(pages)
|
18
|
+
return if pages.empty?
|
19
|
+
|
20
|
+
pages.each do |page|
|
21
|
+
sidebar_html = render_page(page)
|
22
|
+
|
23
|
+
next if sidebar_html.nil?
|
24
|
+
next if page.sidebar_container.nil?
|
25
|
+
|
26
|
+
page.sidebar_container.inner_html = sidebar_html
|
27
|
+
|
28
|
+
page.save
|
29
|
+
|
30
|
+
render_pages(page.children)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def render_page(page)
|
35
|
+
sidebar_html = nil
|
36
|
+
|
37
|
+
begin
|
38
|
+
builder = SidebarHTMLBuilder.new(@tree)
|
39
|
+
sidebar_html = builder.build(page)
|
40
|
+
|
41
|
+
File.open('_site/sidebar.html', 'w') { |f| f.write(sidebar_html) }
|
42
|
+
rescue StandardError => e
|
43
|
+
Jekyll.logger.error(" Sidebar: Unable to render sidebar for '#{page.filename}'.")
|
44
|
+
Jekyll.logger.debug(" Sidebar: #{e.message}. #{e.backtrace.inspect}")
|
45
|
+
return nil
|
46
|
+
end
|
47
|
+
|
48
|
+
sidebar_html
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require_relative 'sidebar_page'
|
4
|
+
|
5
|
+
module SwedbankPay
|
6
|
+
# Builds a plain text representation of a Sidebar, suitable for a terminal.
|
7
|
+
class SidebarTextBuilder
|
8
|
+
def initialize(page)
|
9
|
+
raise ArgumentError, 'Page must be a SidebarPage' unless page.is_a? SidebarPage
|
10
|
+
|
11
|
+
@page = page
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
name = @page.name == '/' ? '/' : "/#{@page.name}"
|
16
|
+
title = @page.title.nil? ? '?' : @page.title.item
|
17
|
+
s = "#{indent} #{name}: #{title} (#{@page.coordinate})\n"
|
18
|
+
|
19
|
+
unless @page.children.empty?
|
20
|
+
@page.children.each do |child|
|
21
|
+
s << child.to_s
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Only strip extraneous whitespace at the root page
|
26
|
+
@page.level.zero? ? s.strip : s
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def indent
|
32
|
+
# Return a special character for the first root page
|
33
|
+
return '┍╾' if (@page.number.nil? || @page.number.zero?) && @page.parent.nil?
|
34
|
+
|
35
|
+
increment = @page.level > 1 ? @page.level + 1 : @page.level
|
36
|
+
|
37
|
+
"┝╾#{('─' * increment)}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def todo
|
41
|
+
# This 'todo' method exists to circumvent the following RuboCop error:
|
42
|
+
# lib/sidebar_text_builder.rb:39:97: C: Style/AsciiComments: Use only ascii symbols in comments.
|
43
|
+
"TODO: Add logic to find the very last page regardless of level and have indent it with '┕╾─'"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require_relative 'sidebar_page_collection'
|
5
|
+
|
6
|
+
module SwedbankPay
|
7
|
+
# Arranges Sidebar pages into a tree
|
8
|
+
class SidebarTreeBuilder
|
9
|
+
include Enumerable
|
10
|
+
extend Forwardable
|
11
|
+
def_delegators :@pages, :each, :length, :empty?, :<<, :[], :count
|
12
|
+
|
13
|
+
def initialize(pages)
|
14
|
+
raise ArgumentError, 'Pages must be a Hash' unless pages.is_a? Hash
|
15
|
+
|
16
|
+
@pages = tree(pages)
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
stringify
|
21
|
+
end
|
22
|
+
|
23
|
+
def inspect
|
24
|
+
stringify(inspection: true)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def stringify(inspection: false)
|
30
|
+
output = "<#{self.class} ##{count}"
|
31
|
+
|
32
|
+
if inspection
|
33
|
+
output << ":\n"
|
34
|
+
@pages.each do |page|
|
35
|
+
output << "#{page}\n"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
output << '>'
|
40
|
+
output
|
41
|
+
end
|
42
|
+
|
43
|
+
def tree(pages)
|
44
|
+
tree = []
|
45
|
+
children_of = {}
|
46
|
+
page_number = 0
|
47
|
+
|
48
|
+
sort_by_path_reversed(pages).each do |_, page|
|
49
|
+
children_of[page.path] = [] if children_of[page.path].nil?
|
50
|
+
page.children = children_of[page.path].sort
|
51
|
+
|
52
|
+
if page.parent.nil?
|
53
|
+
# Root pages are pushed directly into the root of the tree
|
54
|
+
page.number = page_number
|
55
|
+
tree.push(page)
|
56
|
+
page_number += 1
|
57
|
+
else
|
58
|
+
children_of[page.parent] = [] if children_of[page.parent].nil?
|
59
|
+
children_of[page.parent].push(page)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Sort the root pages
|
64
|
+
tree.sort!
|
65
|
+
|
66
|
+
SidebarPageCollection.new(nil, tree)
|
67
|
+
end
|
68
|
+
|
69
|
+
def sort_by_path_reversed(pages)
|
70
|
+
pages.sort_by { |path, _| path }.reverse
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: swedbank-pay-design-guide-jekyll-theme
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Swedbank Pay
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -100,6 +100,20 @@ dependencies:
|
|
100
100
|
- - ">="
|
101
101
|
- !ruby/object:Gem::Version
|
102
102
|
version: '0'
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: jekyll-redirect-from
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :runtime
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
103
117
|
- !ruby/object:Gem::Dependency
|
104
118
|
name: jemoji
|
105
119
|
requirement: !ruby/object:Gem::Requirement
|
@@ -254,7 +268,18 @@ files:
|
|
254
268
|
- assets/tipuesearch/tipuesearch_content.js
|
255
269
|
- assets/tipuesearch/tipuesearch_set.js
|
256
270
|
- lib/gem_version.rb
|
271
|
+
- lib/safe_merge.rb
|
272
|
+
- lib/sanitized_filename.rb
|
257
273
|
- lib/sidebar.rb
|
274
|
+
- lib/sidebar_html_builder.rb
|
275
|
+
- lib/sidebar_page.rb
|
276
|
+
- lib/sidebar_page_collection.rb
|
277
|
+
- lib/sidebar_page_title.rb
|
278
|
+
- lib/sidebar_parser.rb
|
279
|
+
- lib/sidebar_path.rb
|
280
|
+
- lib/sidebar_renderer.rb
|
281
|
+
- lib/sidebar_text_builder.rb
|
282
|
+
- lib/sidebar_tree_builder.rb
|
258
283
|
- lib/swedbank-pay-design-guide-jekyll-theme.rb
|
259
284
|
homepage: https://github.com/SwedbankPay/swedbank-pay-design-guide-jekyll-theme
|
260
285
|
licenses:
|
@@ -268,7 +293,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
268
293
|
requirements:
|
269
294
|
- - ">="
|
270
295
|
- !ruby/object:Gem::Version
|
271
|
-
version:
|
296
|
+
version: 2.4.0
|
272
297
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
273
298
|
requirements:
|
274
299
|
- - ">="
|