swedbank-pay-design-guide-jekyll-theme 1.7 → 1.9.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.
@@ -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,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'jekyll'
4
+ require_relative 'sidebar_page'
5
+
6
+ module SwedbankPay
7
+ # Represents the title of a SidebarPage
8
+ class SidebarPageTitle
9
+ attr_reader :main, :section
10
+
11
+ def self.parse(jekyll_page, sidebar_page)
12
+ raise ArgumentError, 'jekyll_page cannot be nil' if jekyll_page.nil?
13
+ raise ArgumentError, 'jekyll_page must be a Jekyll::Page' unless jekyll_page.is_a? Jekyll::Page
14
+ raise ArgumentError, 'sidebar_page cannot be nil' if sidebar_page.nil?
15
+ raise ArgumentError, 'sidebar_page must be a SidebarPage' unless sidebar_page.is_a? SidebarPage
16
+
17
+ title = jekyll_page['title']
18
+ section = jekyll_page['section']
19
+ return nil if title.nil?
20
+
21
+ SidebarPageTitle.new(title, section, sidebar_page)
22
+ end
23
+
24
+ def lead
25
+ section = find_section(@page)
26
+ return section unless section.nil?
27
+
28
+ @lead
29
+ end
30
+
31
+ def to_s
32
+ @title
33
+ end
34
+
35
+ def inspect
36
+ @title
37
+ end
38
+
39
+ def <=>(other)
40
+ return -1 if other.nil?
41
+
42
+ @title <=> other.to_s
43
+ end
44
+
45
+ private
46
+
47
+ def initialize(title, section, page)
48
+ raise ArgumentError, 'title cannot be nil' if title.nil?
49
+ raise ArgumentError, 'title must be a String' unless title.is_a? String
50
+ raise ArgumentError, 'page cannot be nil' if page.nil?
51
+ raise ArgumentError, 'page must be a SidebarPage' unless page.is_a? SidebarPage
52
+
53
+ @page = page
54
+ @title = title
55
+ parts = title.split('–')
56
+ @section = section
57
+ @lead = parts.first.strip
58
+ @main = parts.last.strip
59
+ end
60
+
61
+ def find_section(page)
62
+ # Return the 'section' front matter if it can be found on the current page.
63
+ return page.title.section unless page.nil? || page.title.nil? || page.title.section.nil? || page.title.section.empty?
64
+
65
+ # Recurse upwards to the root (until there is no parent).
66
+ return find_section(page.parent) unless page.nil? || page.parent.nil?
67
+
68
+ nil
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'jekyll'
4
+ require_relative 'sidebar_path'
5
+
6
+ module SwedbankPay
7
+ # The Sidebar renderer
8
+ class SidebarParser
9
+ def initialize(site)
10
+ raise ArgumentError, 'Site cannot be nil' if site.nil?
11
+ raise ArgumentError, 'Site must be a Jekyll::Site' unless site.is_a? Jekyll::Site
12
+
13
+ @site = site
14
+ end
15
+
16
+ def parse
17
+ pages = build_pages_hash
18
+
19
+ destination = @site.config['destination']
20
+
21
+ Dir.glob("#{destination}/**/*.html") do |filename|
22
+ doc = File.open(filename) { |f| Nokogiri::HTML(f) }
23
+ path = SidebarPath.new(filename).to_s
24
+ page = pages[path]
25
+
26
+ if page.nil?
27
+ Jekyll.logger.debug(" Sidebar: No page found for <#{path}>.")
28
+ next
29
+ end
30
+
31
+ page.doc = doc
32
+ page.filename = filename
33
+ page.headers = find_headers(doc)
34
+ page.sidebar_container = find_sidebar_container(filename, doc)
35
+ end
36
+
37
+ pages
38
+ end
39
+
40
+ private
41
+
42
+ def build_pages_hash
43
+ pages_hash = {}
44
+
45
+ @site.pages.each do |jekyll_page|
46
+ sidebar_page = SidebarPage.new(jekyll_page)
47
+ pages_hash[sidebar_page.path] = sidebar_page
48
+ end
49
+
50
+ pages_hash
51
+ end
52
+
53
+ def find_headers(doc)
54
+ headers = []
55
+
56
+ doc.xpath('//h2').each do |header|
57
+ next unless header['id']
58
+
59
+ child_markup = header.last_element_child
60
+ header = {
61
+ id: header['id'],
62
+ title: header.content.strip,
63
+ hash: (child_markup['href']).to_s
64
+ }
65
+ headers.push(header)
66
+ end
67
+
68
+ headers
69
+ end
70
+
71
+ def find_sidebar_container(filename, doc)
72
+ sidebar_containers = doc.xpath('//*[@id="dx-sidebar-main-nav-ul"]')
73
+
74
+ unless sidebar_containers.any?
75
+ Jekyll.logger.debug(" Sidebar: No sidebar container found in #{filename}")
76
+ return nil
77
+ end
78
+
79
+ sidebar_containers.first
80
+ end
81
+ end
82
+ 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,70 @@
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 initialize(tree)
9
+ raise ArgumentError, 'pages cannot be nil' if tree.nil?
10
+ raise ArgumentError, 'pages must be an SidebarTreeBuilder' unless tree.is_a? SidebarTreeBuilder
11
+
12
+ @tree = tree
13
+ end
14
+
15
+ def enrich_jekyll
16
+ enrich_jekyll_pages(@tree)
17
+ end
18
+
19
+ def render
20
+ render_pages(@tree)
21
+ end
22
+
23
+ private
24
+
25
+ def enrich_jekyll_pages(pages)
26
+ return if pages.empty?
27
+
28
+ pages.each do |page|
29
+ page.enrich_jekyll
30
+
31
+ enrich_jekyll_pages(page.children)
32
+ end
33
+ end
34
+
35
+ def render_pages(pages)
36
+ return if pages.empty?
37
+
38
+ pages.each do |page|
39
+ sidebar_html = render_page(page)
40
+
41
+ next if sidebar_html.nil?
42
+ next if page.sidebar_container.nil?
43
+
44
+ page.sidebar_container.inner_html = sidebar_html
45
+
46
+ page.save
47
+
48
+ render_pages(page.children)
49
+ end
50
+ end
51
+
52
+ def render_page(page)
53
+ sidebar_html = nil
54
+
55
+ begin
56
+ builder = SidebarHTMLBuilder.new(@tree)
57
+ sidebar_html = builder.build(page)
58
+
59
+ File.open('_site/sidebar.html', 'w') { |f| f.write(sidebar_html) }
60
+ rescue StandardError => e
61
+ name = page.filename || page.name
62
+ Jekyll.logger.error(" Sidebar: Unable to render sidebar for '#{name}'.")
63
+ Jekyll.logger.debug(" Sidebar: #{e.message}. #{e.backtrace.inspect}")
64
+ return nil
65
+ end
66
+
67
+ sidebar_html
68
+ end
69
+ end
70
+ 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.main
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