jekyll-potion 1.0.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.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +202 -0
  3. data/jekyll-potion.gemspec +17 -0
  4. data/lib/jekyll-potion/logger.rb +49 -0
  5. data/lib/jekyll-potion/models/favicon.rb +28 -0
  6. data/lib/jekyll-potion/models/page-potion.rb +86 -0
  7. data/lib/jekyll-potion/models/potion-page.rb +26 -0
  8. data/lib/jekyll-potion/models/potion-source-map-page.rb +15 -0
  9. data/lib/jekyll-potion/models/potion-static-file.rb +21 -0
  10. data/lib/jekyll-potion/potion.rb +136 -0
  11. data/lib/jekyll-potion/processor/base/jquery-3.6.0.min.js +2 -0
  12. data/lib/jekyll-potion/processor/base-template/code.js +40 -0
  13. data/lib/jekyll-potion/processor/base-template/navigation.js +43 -0
  14. data/lib/jekyll-potion/processor/base-template/tabs.js +38 -0
  15. data/lib/jekyll-potion/processor/header-template/header.js +31 -0
  16. data/lib/jekyll-potion/processor/make-base-javascript-processor.rb +59 -0
  17. data/lib/jekyll-potion/processor/make-date-processor.rb +30 -0
  18. data/lib/jekyll-potion/processor/make-empty-content-processor.rb +19 -0
  19. data/lib/jekyll-potion/processor/make-favicon-processor.rb +108 -0
  20. data/lib/jekyll-potion/processor/make-front-matter-processor.rb +21 -0
  21. data/lib/jekyll-potion/processor/make-header-link-processor.rb +103 -0
  22. data/lib/jekyll-potion/processor/make-navigation-processor.rb +55 -0
  23. data/lib/jekyll-potion/processor/make-og-tag-processor.rb +45 -0
  24. data/lib/jekyll-potion/processor/make-search-index-processor.rb +205 -0
  25. data/lib/jekyll-potion/processor/make-theme-processor.rb +197 -0
  26. data/lib/jekyll-potion/processor/make-title-processor.rb +53 -0
  27. data/lib/jekyll-potion/processor/rewrite-a-href-processor.rb +43 -0
  28. data/lib/jekyll-potion/processor/rewrite-img-processor.rb +42 -0
  29. data/lib/jekyll-potion/processor/search-template/search.js +123 -0
  30. data/lib/jekyll-potion/processor.rb +152 -0
  31. data/lib/jekyll-potion/site.rb +155 -0
  32. data/lib/jekyll-potion/tag.rb +176 -0
  33. data/lib/jekyll-potion/tags/alerts.rb +24 -0
  34. data/lib/jekyll-potion/tags/api.rb +105 -0
  35. data/lib/jekyll-potion/tags/code.rb +65 -0
  36. data/lib/jekyll-potion/tags/empty.rb +20 -0
  37. data/lib/jekyll-potion/tags/file.rb +22 -0
  38. data/lib/jekyll-potion/tags/link.rb +47 -0
  39. data/lib/jekyll-potion/tags/logo.rb +22 -0
  40. data/lib/jekyll-potion/tags/navigation.rb +35 -0
  41. data/lib/jekyll-potion/tags/pagination.rb +20 -0
  42. data/lib/jekyll-potion/tags/tabs.rb +62 -0
  43. data/lib/jekyll-potion/theme/proto/_includes/container.html +10 -0
  44. data/lib/jekyll-potion/theme/proto/_includes/head.html +4 -0
  45. data/lib/jekyll-potion/theme/proto/_includes/header.html +21 -0
  46. data/lib/jekyll-potion/theme/proto/_includes/image.html +5 -0
  47. data/lib/jekyll-potion/theme/proto/_includes/nav.html +3 -0
  48. data/lib/jekyll-potion/theme/proto/_includes/search.html +29 -0
  49. data/lib/jekyll-potion/theme/proto/_layouts/default.html +19 -0
  50. data/lib/jekyll-potion/theme/proto/_layouts/error.html +23 -0
  51. data/lib/jekyll-potion/theme/proto/_templates/alerts.liquid +4 -0
  52. data/lib/jekyll-potion/theme/proto/_templates/api.liquid +46 -0
  53. data/lib/jekyll-potion/theme/proto/_templates/api=description.liquid +3 -0
  54. data/lib/jekyll-potion/theme/proto/_templates/api=parameter.liquid +5 -0
  55. data/lib/jekyll-potion/theme/proto/_templates/api=response.liquid +7 -0
  56. data/lib/jekyll-potion/theme/proto/_templates/code.liquid +8 -0
  57. data/lib/jekyll-potion/theme/proto/_templates/empty.liquid +15 -0
  58. data/lib/jekyll-potion/theme/proto/_templates/file.liquid +8 -0
  59. data/lib/jekyll-potion/theme/proto/_templates/link.liquid +9 -0
  60. data/lib/jekyll-potion/theme/proto/_templates/logo.liquid +8 -0
  61. data/lib/jekyll-potion/theme/proto/_templates/navigation-page.liquid +14 -0
  62. data/lib/jekyll-potion/theme/proto/_templates/navigation.liquid +5 -0
  63. data/lib/jekyll-potion/theme/proto/_templates/pagination.liquid +30 -0
  64. data/lib/jekyll-potion/theme/proto/_templates/tabs.liquid +8 -0
  65. data/lib/jekyll-potion/theme/proto/_templates/tabs=content.liquid +5 -0
  66. data/lib/jekyll-potion/theme/proto/assets/css/main.scss +1254 -0
  67. data/lib/jekyll-potion/theme/proto/assets/css/syntax.css +80 -0
  68. data/lib/jekyll-potion/theme/proto/assets/js/jsrender.min.js +4 -0
  69. data/lib/jekyll-potion/theme/proto/assets/js/jsrender.min.js.map +1 -0
  70. data/lib/jekyll-potion/theme/proto/assets/js/main.js +237 -0
  71. data/lib/jekyll-potion/theme.rb +165 -0
  72. data/lib/jekyll-potion/util.rb +73 -0
  73. data/lib/jekyll-potion.rb +32 -0
  74. metadata +143 -0
@@ -0,0 +1,42 @@
1
+ # SPDX-FileCopyrightText: Copyright 2022 SK TELECOM CO., LTD.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ module Jekyll::Potion
5
+ class RewriteImgProcessor < Processor
6
+ HTTP_SCHEME = %r!\Ahttp(s)?://!im.freeze
7
+ ABSOLUTE_PATH = %r!\A/!im.freeze
8
+
9
+ RELATIVE_SRC = %r!src\s*="(?<src>\.+[^"]*?)"!im.freeze
10
+
11
+ def page_post_render(page, html, modified)
12
+ if modified
13
+ src_count = 0
14
+ inline_count = 0
15
+
16
+ html.css("img[src]").each { |img_tag|
17
+ src = img_tag["src"]
18
+
19
+ next if img_tag.has_attribute?(@config[:skip_keyword])
20
+ next if src.strip.empty?
21
+
22
+ unless img_tag.parent.text.strip.empty?
23
+ inline_count += 1
24
+ img_tag.add_class(@config[:inline_image_class])
25
+ end
26
+
27
+ next if src =~ HTTP_SCHEME || src =~ ABSOLUTE_PATH
28
+
29
+ src_count += 1
30
+ img_tag["src"] = @site.base_absolute_url(File.dirname(page.path), src)
31
+ img_tag.add_class(@config[:internal_image_class])
32
+ }
33
+
34
+ if src_count > 0 || inline_count > 0
35
+ @logger.trace("#{page.name} #{src_count} img tags replace absolute path") if src_count > 0
36
+ @logger.trace("#{page.name} #{inline_count} inline img tags add class") if inline_count > 0
37
+ yield html
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,123 @@
1
+ // SPDX-FileCopyrightText: Copyright 2022 SK TELECOM CO., LTD.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ (($) => {
5
+ class SearchResults {
6
+ constructor(keyword, per_size) {
7
+ this.page_index_line_numbers_map = new Map()
8
+ this.keyword = keyword
9
+ this.per_size = per_size
10
+ this.search_results = []
11
+ }
12
+
13
+ contains(page, index, line_number) {
14
+ if (!this.page_index_line_numbers_map.has(page.url)) {
15
+ this.page_index_line_numbers_map.set(page.url, new Map())
16
+ }
17
+
18
+ if (!this.page_index_line_numbers_map.get(page.url).has(index.hash)) {
19
+ this.page_index_line_numbers_map.get(page.url).set(index.hash, [])
20
+ }
21
+
22
+ return this.page_index_line_numbers_map.get(page.url).get(index.hash).find(line_numbers => line_numbers.includes(line_number))
23
+ }
24
+
25
+ static create_line_numbers(line_number, total_size, per_size) {
26
+ let start = Math.max(0, line_number - (Math.floor(per_size / 2) - (1 - (per_size % 2))))
27
+ let end = Math.min(total_size, start + per_size)
28
+
29
+ let n = []
30
+
31
+ for (start; start < end; start++) {
32
+ n.push(start)
33
+ }
34
+
35
+ return n
36
+ }
37
+
38
+ add_line_number(page, index, index_order, line_number) {
39
+ if (!this.contains(page, index, line_number)) {
40
+ let line_numbers = SearchResults.create_line_numbers(line_number, index.sentences.length, this.per_size)
41
+ this.page_index_line_numbers_map.get(page.url).get(index.hash).push(line_numbers)
42
+
43
+ this.search_results.push(new SearchResult(page, index, index_order, this.keyword, line_number, line_numbers))
44
+ }
45
+ }
46
+
47
+ result() {
48
+ this.search_results.sort((r1, r2) => {
49
+ if (r1.page_order === r2.page_order) {
50
+ if (r1.index_order === r2.index_order) {
51
+ return r1.line_number - r2.line_number
52
+ }
53
+
54
+ return r1.index_order - r2.index_order
55
+ }
56
+
57
+ return r1.page_order - r2.page_order
58
+ })
59
+
60
+ return this.search_results
61
+ }
62
+ }
63
+
64
+ class SearchResult {
65
+ constructor(page, index, index_order, keyword, line_number, line_numbers) {
66
+ this.url = page.url + index.hash
67
+ this.title = index.title
68
+ this.page_order = page.order
69
+ this.index_order = index_order
70
+ this.line_number = line_number
71
+ this.sentences = line_numbers.map(n => index.sentences[n].replace(new RegExp('(' + keyword + ')', 'gi'), '<code>$1</code>'))
72
+ }
73
+ }
74
+
75
+ class Search {
76
+ constructor(options) {
77
+ this.options = options
78
+ this.loaded = false
79
+ this.page_indexes = []
80
+ }
81
+
82
+ init() {
83
+ }
84
+
85
+ load_search_file(callback) {
86
+ $.getJSON('{{ search_file }}', data => {
87
+ this.loaded = true
88
+ this.page_indexes = data
89
+ if (callback) {
90
+ callback.call(this)
91
+ }
92
+ })
93
+ }
94
+
95
+ search(keyword, context, callback) {
96
+ if (this.loaded) {
97
+ let search_results = new SearchResults(keyword, 3)
98
+
99
+ this.page_indexes.forEach((page) => {
100
+ page.indexes.forEach((index, index_order) => {
101
+ index.sentences.forEach((sentence, line_number) => {
102
+ if (new RegExp(keyword, 'i').test(sentence)) {
103
+ search_results.add_line_number(page, index, index_order, line_number)
104
+ }
105
+ })
106
+ })
107
+ })
108
+
109
+ if (callback && callback instanceof Function) {
110
+ callback.call(context, search_results.result())
111
+ }
112
+ } else {
113
+ this.load_search_file(() => {
114
+ this.search(keyword, context, callback)
115
+ })
116
+ }
117
+ }
118
+ }
119
+
120
+ $.search = (options) => {
121
+ return new Search(options)
122
+ }
123
+ })(jQuery)
@@ -0,0 +1,152 @@
1
+ # SPDX-FileCopyrightText: Copyright 2022 SK TELECOM CO., LTD.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ require "nokogiri"
5
+
6
+ module Jekyll::Potion
7
+ class ProcessorsConfig
8
+ DEFAULT_PROCESSORS_CONFIG = {
9
+ :make_header_link_processor => {
10
+ :selector => "data-header-link",
11
+ :hash_class => "go-hash",
12
+ :copy_class => "copy-link"
13
+ },
14
+ :rewrite_img_processor => {
15
+ :skip_keyword => "data-skip-src-to-absolute",
16
+ :inline_image_class => "img-inline",
17
+ :internal_image_class => "img-internal"
18
+ },
19
+ :rewrite_a_href_processor => {
20
+ :skip_keyword => "data-skip-href-to-absolute",
21
+ :index_page_keyword => "data-to-index-page",
22
+ :hash_link_class => "hash-internal",
23
+ :internal_link_class => "a-internal"
24
+ },
25
+ :make_search_index_processor => {
26
+ :skip_keyword => "data-skip-search-index",
27
+ :search_file_name => "search.json"
28
+ }
29
+ }.freeze
30
+
31
+ def initialize(config)
32
+ @config = Util.extract(DEFAULT_PROCESSORS_CONFIG, config)
33
+ end
34
+
35
+ def [] (processor)
36
+ @config[processor]
37
+ end
38
+ end
39
+
40
+ class Processor
41
+ @@priority = {}
42
+
43
+ DEFAULT_PRIORITY = {
44
+ :site_after_init => :lowest,
45
+ :site_pre_render => :lowest,
46
+ :site_post_read => :lowest,
47
+ :page_pre_render => :lowest,
48
+ :page_post_render => :lowest,
49
+ :site_post_render => :lowest
50
+ }.freeze
51
+
52
+ PRIORITY_MAP = {
53
+ :lowest => 0,
54
+ :low => 10,
55
+ :normal => 20,
56
+ :high => 30,
57
+ :highest => 40,
58
+ }.freeze
59
+
60
+ METHODS = [
61
+ :site_after_init,
62
+ :site_post_read,
63
+ :site_pre_render,
64
+ :page_pre_render,
65
+ :page_post_render,
66
+ :site_post_render
67
+ ].freeze
68
+
69
+ DEFAULT_PROCESSORS = [
70
+ :make_base_javascript_processor,
71
+ :make_theme_processor,
72
+ :make_front_matter_processor,
73
+ :make_title_processor,
74
+ :make_date_processor,
75
+ :make_favicon_processor
76
+ ].freeze
77
+
78
+ SELECTABLE_PROCESSORS = [
79
+ :make_navigation_processor,
80
+ :make_empty_content_processor,
81
+ :make_header_link_processor,
82
+ :rewrite_img_processor,
83
+ :rewrite_a_href_processor,
84
+ :make_search_index_processor,
85
+ :make_og_tag_processor
86
+ ].freeze
87
+
88
+ ALL_PROCESSORS = [DEFAULT_PROCESSORS, SELECTABLE_PROCESSORS].flatten
89
+
90
+ attr_reader :priority
91
+
92
+ def initialize(site, theme, config, tags)
93
+ @site = site
94
+ @theme = theme
95
+ @config = config
96
+ @tags = tags
97
+ @logger = Logger.new(self)
98
+ @priority = Util.extract(DEFAULT_PRIORITY, @@priority, false)
99
+ @@priority = {}
100
+ end
101
+
102
+ def site_after_init(site) end
103
+
104
+ def site_pre_render(site) end
105
+
106
+ def site_post_read(site) end
107
+
108
+ def site_post_render(site) end
109
+
110
+ def page_pre_render(page, html, modified) end
111
+
112
+ def page_post_render(page, html, modified) end
113
+
114
+ def find_priority(method)
115
+ if @priority[method].is_a?(Numeric)
116
+ @priority[method]
117
+ else
118
+ PRIORITY_MAP[@priority[method]]
119
+ end
120
+ end
121
+
122
+ def self.priority(event, priority)
123
+ @@priority[event] = priority
124
+ end
125
+
126
+ def self.load_processors(site, theme, processors, tags, processor_names)
127
+ active_processor_names = []
128
+ active_processor_names.concat(DEFAULT_PROCESSORS)
129
+
130
+ processor_names.map { |active_processor_name| active_processor_name.to_sym }
131
+ .select { |active_processor_symbol| SELECTABLE_PROCESSORS.any?(active_processor_symbol) }
132
+ .each { |active_processor_symbol| active_processor_names << active_processor_symbol }
133
+
134
+ active_processor_names.map { |processor_symbol|
135
+ processor_name = processor_symbol.to_s.gsub("_", "-")
136
+
137
+ require_relative "processor/#{processor_name}.rb"
138
+
139
+ constants = Jekyll::Potion.constants.select { |c|
140
+ c.downcase.to_s == processor_name.to_s.gsub(/-/, "").downcase
141
+ }
142
+
143
+ raise SyntaxError, "undefined #{processor_name} class" if constants.empty?
144
+ raise SyntaxError, "duplicate #{processor_name} class" if constants.size > 1
145
+
146
+ Logger.trace(name, "load processor", processor_name)
147
+
148
+ Jekyll::Potion.const_get(constants.first).new(site, theme, processors[processor_symbol], tags)
149
+ }
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,155 @@
1
+ # SPDX-FileCopyrightText: Copyright 2022 SK TELECOM CO., LTD.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ module Jekyll::Potion
5
+ class Url
6
+ attr_reader :url
7
+ attr_reader :path
8
+ attr_reader :name
9
+
10
+ def initialize(path)
11
+ @url = "/#{path}"
12
+ @path = File.dirname(path)
13
+ @name = File.basename(path)
14
+ end
15
+ end
16
+
17
+ class Site
18
+ DEFAULT_SITE_CONFIG = {
19
+ :index_page => "",
20
+ :permalink => "",
21
+ :title => "",
22
+ :icon => "",
23
+ :theme => "proto",
24
+ :favicon => "",
25
+ :exclude => []
26
+ }
27
+
28
+ def initialize(potion_base_dir, site, config)
29
+ @site = site
30
+ @config = Util.extract(DEFAULT_SITE_CONFIG, config)
31
+ @config[:potion_base_dir] = potion_base_dir
32
+ @config[:processor_base_dir] = File.join(potion_base_dir, "processor")
33
+
34
+ @navigation = nil
35
+ @navigation_result = ""
36
+ end
37
+
38
+ def [] (key)
39
+ @config[key]
40
+ end
41
+
42
+ def empty?(key)
43
+ not @config.has_key?(key) or @config[key].nil? or @config[key].empty?
44
+ end
45
+
46
+ def baseurl
47
+ @site.config["baseurl"] ||= ""
48
+ end
49
+
50
+ def url
51
+ @site.config["url"] ||= ""
52
+ end
53
+
54
+ def absolute_url(base, path, *args)
55
+ Pathname.new(File.join(base, File.join(path, *args))).cleanpath.to_s
56
+ end
57
+
58
+ def base_absolute_url(path, *args)
59
+ absolute_url(baseurl, path, *args)
60
+ end
61
+
62
+ def base_url(*args)
63
+ File.join(baseurl, *args)
64
+ end
65
+
66
+ def to_url(base, path, *args)
67
+ Url.new(absolute_url(base, path, args))
68
+ end
69
+
70
+ def index_url
71
+ base_url("")
72
+ end
73
+
74
+ def full_url(*args)
75
+ File.join(url, base_url(*args))
76
+ end
77
+
78
+ def page_title(page)
79
+ if empty?(:title)
80
+ page.data["title"]
81
+ else
82
+ "#{@config[:title]} - #{page.data["title"]}"
83
+ end
84
+ end
85
+
86
+ def static_file(base, dir, name, target)
87
+ PotionStaticFile.new(@site, base, dir, name, target)
88
+ end
89
+
90
+ def potion_page(base, dir, name, target)
91
+ PotionPage.new(@site, base, dir, name, target)
92
+ end
93
+
94
+ def page(base, dir, name)
95
+ Jekyll::Page.new(@site, base, dir, name)
96
+ end
97
+
98
+ def static_to_page(static_page)
99
+ base = static_page.instance_variable_get("@base")
100
+ dir = static_page.instance_variable_get("@dir")
101
+ name = static_page.instance_variable_get("@name")
102
+
103
+ page(base, dir, name)
104
+ end
105
+
106
+ def markdown_converter
107
+ @site.find_converter_instance(Jekyll::Converters::Markdown)
108
+ end
109
+
110
+ def markdown_pages
111
+ @site.pages.select { |page| markdown_converter.matches(page.extname) }
112
+ end
113
+
114
+ def static_markdown_files
115
+ @site.static_files.select { |file| markdown_converter.matches(file.extname) }
116
+ end
117
+
118
+ def scss_converter
119
+ @site.find_converter_instance(Jekyll::Converters::Scss)
120
+ end
121
+
122
+ def scss_convert(body)
123
+ scss_converter.convert(body)
124
+ end
125
+
126
+ def markdown_convert(body)
127
+ markdown_converter.convert(body)
128
+ end
129
+
130
+ def replace_scss_ext(file_name)
131
+ "#{File.basename(file_name, ".*")}#{scss_converter.output_ext(File.extname(file_name))}"
132
+ end
133
+
134
+ def read_file(path)
135
+ File.read(path)
136
+ end
137
+
138
+ def load_template(path)
139
+ Liquid::Template.parse(read_file(path))
140
+ end
141
+
142
+ def jsonify(path)
143
+ JSON.parse(read_file(File.join(@site.source, path)))
144
+ end
145
+
146
+ def navigation(root_potions)
147
+ @navigation = root_potions
148
+ end
149
+
150
+ def render_navigation(tag)
151
+ @navigation_result = tag.render_only_one(@navigation) if @navigation_result.empty?
152
+ @navigation_result
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,176 @@
1
+ # SPDX-FileCopyrightText: Copyright 2022 SK TELECOM CO., LTD.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ module Jekyll::Potion
5
+ class TagsConfig
6
+ DEFAULT_TAGS_CONFIG = {
7
+ :alerts => {
8
+ :info => "info",
9
+ :warning => "warning",
10
+ :danger => "danger",
11
+ :success => "success"
12
+ },
13
+ :code => {
14
+ :code_class => "code",
15
+ :success_class => "copy-text",
16
+ :success_show_class => "show"
17
+ },
18
+ :tabs => {
19
+ :tabs_class => "tabs",
20
+ :active_class => "active"
21
+ },
22
+ :navigation => {
23
+ :active_class => "active",
24
+ :fold_class => "fold"
25
+ }
26
+ }.freeze
27
+
28
+ def initialize(config)
29
+ @config = Util.extract(DEFAULT_TAGS_CONFIG, config)
30
+ end
31
+
32
+ def [] (tag_name)
33
+ Util.string_key_hash(@config[tag_name])
34
+ end
35
+ end
36
+
37
+ module PotionTag
38
+ TEMPLATE_DELIMITER = "-"
39
+ ATTRIBUTES_REGEX = /(\S*)="(.*?[^\\])"/
40
+ POTION_TAG_PARAM_REGEX = /(?:#{TEMPLATE_DELIMITER}(\S*) )?((?:#{ATTRIBUTES_REGEX}\s?)*)/
41
+ POTION_BLOCK_DELIMITER = "::"
42
+ POTION_BLOCK_DELIMITER_REPLACE = "="
43
+
44
+ attr_accessor :id
45
+ attr_accessor :template_name
46
+ attr_accessor :logger
47
+
48
+ @@registry = {}
49
+
50
+ def initialize(tag_name, markup, options)
51
+ super
52
+ @tag_name = tag_name
53
+ @end_tag_name = "{% end#{tag_name} %}"
54
+ @options = options
55
+ @id = id_format
56
+
57
+ @template_name = "#{tag_name}"
58
+ @params = {}
59
+
60
+ if markup =~ POTION_TAG_PARAM_REGEX
61
+ @template_name << "-#{$1}" unless $1.nil?
62
+ @params = attr_to_hash($2) unless $2.nil?
63
+ end
64
+
65
+ @logger = Logger.new(self)
66
+
67
+ if @template_name.include?(POTION_BLOCK_DELIMITER)
68
+ @template_name.sub!(POTION_BLOCK_DELIMITER, POTION_BLOCK_DELIMITER_REPLACE)
69
+ end
70
+ end
71
+
72
+ def id_format
73
+ "#{@tag_name}-#{@options.line_number}"
74
+ end
75
+
76
+ def attr_to_hash(str)
77
+ str.scan(ATTRIBUTES_REGEX).to_h.map { |k, v| [k.strip, v.strip] }.to_h
78
+ end
79
+
80
+ def ensure_valid_attr(*keys)
81
+ keys.each { |key|
82
+ unless @params.has_key?(key)
83
+ raise SyntaxError, "#{@tag_name} required #{key} attribute"
84
+ end
85
+ }
86
+ end
87
+ end
88
+
89
+ class PotionBlock < Liquid::Block
90
+ include PotionTag
91
+
92
+ attr_accessor :elements
93
+
94
+ FULL_TOKEN = /\A\{%\s*(\w+#{PotionTag::POTION_BLOCK_DELIMITER}(\w+))\s*(.*?)%}\z/om
95
+
96
+ def initialize(tag_name, markup, options)
97
+ super
98
+ @elements = []
99
+ end
100
+
101
+ def parse(tokens)
102
+ options.line_number = tokens.line_number
103
+ while (token = tokens.shift)
104
+ next if token.empty?
105
+
106
+ if token == @end_tag_name
107
+ return
108
+ end
109
+
110
+ if token =~ FULL_TOKEN
111
+ tag_name = $1
112
+ markup = $3
113
+
114
+ child_tag_class = @@registry[$2]
115
+
116
+ unless child_tag_class.nil?
117
+ @elements << child_tag_class.parse(tag_name, markup, tokens, options)
118
+ end
119
+ end
120
+ @options.line_number = tokens.line_number
121
+ end
122
+ end
123
+
124
+ def nodelist
125
+ @elements
126
+ end
127
+
128
+ def blank?
129
+ @elements.empty?
130
+ end
131
+
132
+ def self.registered_tag(tag_name)
133
+ return nil unless @@registry.has_key?(tag_name)
134
+ @@registry[tag_name]
135
+ end
136
+
137
+ def self.register_tag(tag_name, tag_class)
138
+ @@registry[tag_name] = tag_class
139
+ end
140
+ end
141
+
142
+ module PotionBlockElement
143
+ include PotionTag
144
+
145
+ MAX_DEPTH = 100
146
+
147
+ def block_delimiter
148
+ "end#{tag_name}"
149
+ end
150
+
151
+ def parse_body(body, tokens)
152
+ if parse_context.depth >= MAX_DEPTH
153
+ raise StackLevelError, "Nesting too deep".freeze
154
+ end
155
+ parse_context.depth += 1
156
+ begin
157
+ body.parse(tokens, parse_context) do |end_tag_name, end_tag_params|
158
+ @blank &&= body.blank?
159
+
160
+ return false if "#{end_tag_name}#{end_tag_params}".strip == block_delimiter
161
+ unless end_tag_name
162
+ raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_never_closed".freeze, block_name: block_name))
163
+ end
164
+
165
+ # this tag is not registered with the system
166
+ # pass it to the current block for special handling or error reporting
167
+ unknown_tag(end_tag_name, end_tag_params, tokens)
168
+ end
169
+ ensure
170
+ parse_context.depth -= 1
171
+ end
172
+
173
+ true
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,24 @@
1
+ # SPDX-FileCopyrightText: Copyright 2022 SK TELECOM CO., LTD.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ module Jekyll::Potion
5
+ class AlertsTag < Liquid::Block
6
+ include PotionTag
7
+
8
+ def initialize(tag_name, markup, options)
9
+ super
10
+ ensure_valid_attr("style")
11
+ end
12
+
13
+ def render(page_context)
14
+ config = Potion[:tags][:alerts]
15
+
16
+ @params["style"] = config[@params["style"]] if config.has_key?(@params["style"])
17
+ @params["body"] = Potion[:site].markdown_convert(super)
18
+
19
+ Potion[:theme].render_template(@template_name, @params)
20
+ end
21
+ end
22
+ end
23
+
24
+ Liquid::Template.register_tag("alerts", Jekyll::Potion::AlertsTag)