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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0a1983ca9e2e623d45572e71e44d145376ad1ea114526c130de81ddcbc58546d
4
- data.tar.gz: c6403598ba456a0008c4e1d2545379faf4df3ad7c602c340efcf56b58d722d74
3
+ metadata.gz: 4baacc614edb524f53a8b0a23788382fba5ec477f10f08888adf08fcbde24998
4
+ data.tar.gz: 0cb1ef91541ba25c94708789ab05379ea92fc94ea0a7a62c336182f108a62544
5
5
  SHA512:
6
- metadata.gz: d43cbc52a6b2015129e380a6dea2b4435eb6819be17af50094ce1cfe694d172759f7bc4b6371822854480c20b1a5559ed347970a1e77a7f616b6dfd1c6196f03
7
- data.tar.gz: d8caa50f52475c619eefc3f96ae3e0985bf71dfde786e68f5b16031c5173cdb1fe5f8833a7bdb82bbee09b77b6bd535308bddf55f756acfaafb8f2507fae3a21
6
+ metadata.gz: 0bf78e21de260346ee939876981e7cfeb2558e74a2d492217a07c4a23bde14018eb746225e7ad5f23420cacf89c2c82e07dc8c008a2ed588e7a5a9934ea2862f
7
+ data.tar.gz: bba4b0c952ee13e087c0e6f38c738d3999874e0670a3881e053b2b7fc58ae5e39ec748af3d64e3548c45efe79e9984539f193340ebaf73263e10ebddcdbe74e4
@@ -1,2 +1,3 @@
1
1
  # frozen_string_literal: false
2
- require_relative '../lib/sidebar.rb'
2
+
3
+ require_relative '../lib/sidebar'
@@ -4,7 +4,7 @@ module Gem
4
4
  # Gem Specification
5
5
  class Specification
6
6
  def self.gem_version
7
- '1.8.1'
7
+ '1.9.0'
8
8
  end
9
9
  end
10
10
  end
@@ -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
@@ -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 Jekyll
11
+ module SwedbankPay
8
12
  # A nice sidebar
9
- class Sidebar
10
- attr_accessor :hash_pre_render
11
- attr_accessor :filename_with_headers
13
+ module Sidebar
14
+ class << self
15
+ attr_reader :pages
12
16
 
13
- def initialize
14
- @hash_pre_render = {}
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
- File.open('_site/sidebar.html', 'w') { |f| f.write(sidebar) }
161
- sidebar
162
- end
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
- exact ? filename == url : filename.start_with?(url)
174
- end
175
-
176
- def merge(hash1, hash2)
177
- all_keys = hash1.keys | hash2.keys
178
- result_hash = {}
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
- sidebar = Jekyll::Sidebar.new
38
+ SwedbankPay::Sidebar.init
204
39
 
205
- Jekyll::Hooks.register :site, :pre_render do |site, _payload|
40
+ Jekyll::Hooks.register :site, :pre_render do |site, _|
206
41
  site.pages.each do |page|
207
- sidebar.pre_render page
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
- sidebar.post_write site
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
@@ -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
@@ -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.8.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-09-17 00:00:00.000000000 Z
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: '0'
296
+ version: 2.4.0
272
297
  required_rubygems_version: !ruby/object:Gem::Requirement
273
298
  requirements:
274
299
  - - ">="