jekyll-wikilinks 0.0.5 → 0.0.9
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.
- checksums.yaml +4 -4
- data/lib/jekyll-wikilinks/config.rb +113 -0
- data/lib/jekyll-wikilinks/patch/context.rb +19 -0
- data/lib/jekyll-wikilinks/patch/doc_manager.rb +106 -0
- data/lib/jekyll-wikilinks/patch/site.rb +12 -0
- data/lib/jekyll-wikilinks/plugins/converter.rb +53 -0
- data/lib/jekyll-wikilinks/plugins/filter.rb +81 -0
- data/lib/jekyll-wikilinks/plugins/generator.rb +41 -0
- data/lib/jekyll-wikilinks/util/link_index.rb +89 -0
- data/lib/jekyll-wikilinks/util/parser.rb +169 -0
- data/lib/jekyll-wikilinks/util/regex.rb +72 -0
- data/lib/jekyll-wikilinks/util/wikilink.rb +278 -0
- data/lib/jekyll-wikilinks/version.rb +7 -3
- data/lib/jekyll-wikilinks.rb +22 -183
- metadata +46 -13
- data/lib/jekyll-wikilinks/context.rb +0 -15
- data/lib/jekyll-wikilinks/doc_manager.rb +0 -68
- data/lib/jekyll-wikilinks/filter.rb +0 -39
- data/lib/jekyll-wikilinks/jekyll_patch.rb +0 -24
- data/lib/jekyll-wikilinks/link_index.rb +0 -81
- data/lib/jekyll-wikilinks/naming_const.rb +0 -21
- data/lib/jekyll-wikilinks/parser.rb +0 -237
@@ -0,0 +1,169 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
require_relative "regex"
|
3
|
+
require_relative "wikilink"
|
4
|
+
|
5
|
+
module Jekyll
|
6
|
+
module WikiLinks
|
7
|
+
|
8
|
+
# more of a "parser" than a parser
|
9
|
+
class Parser
|
10
|
+
attr_accessor :doc_manager, :markdown_converter, :wikilink_inlines, :wikilink_blocks
|
11
|
+
|
12
|
+
# Use Jekyll's native relative_url filter
|
13
|
+
include Jekyll::Filters::URLFilters
|
14
|
+
|
15
|
+
CONVERTER_CLASS = Jekyll::Converters::Markdown
|
16
|
+
|
17
|
+
def initialize(site)
|
18
|
+
@context ||= Jekyll::WikiLinks::Context.new(site)
|
19
|
+
# do not use @dm in parser -- it is only meant to be passed down into wikilink classes.
|
20
|
+
@doc_manager ||= site.doc_mngr
|
21
|
+
@markdown_converter ||= site.find_converter_instance(CONVERTER_CLASS)
|
22
|
+
@wikilink_blocks, @wikilink_inlines = [], []
|
23
|
+
end
|
24
|
+
|
25
|
+
# parsing
|
26
|
+
|
27
|
+
def parse(doc_filename, doc_content)
|
28
|
+
@wikilink_blocks, @wikilink_inlines = [], []
|
29
|
+
if !$wiki_conf.disabled_attributes?
|
30
|
+
self.parse_blocks(doc_filename, doc_content)
|
31
|
+
end
|
32
|
+
self.parse_inlines(doc_filename, doc_content)
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_blocks(doc_filename, doc_content)
|
36
|
+
block_matches = doc_content.scan(REGEX_WIKI_LINK_BLOCKS)
|
37
|
+
if !block_matches.nil? && block_matches.size != 0
|
38
|
+
block_matches.each do |wl_match|
|
39
|
+
# init block wikilink
|
40
|
+
wikilink_block = WikiLinkBlock.new(
|
41
|
+
@doc_manager,
|
42
|
+
doc_filename,
|
43
|
+
wl_match[0], # link_type
|
44
|
+
wl_match[2], # bullet_type
|
45
|
+
)
|
46
|
+
# extract + add filenames
|
47
|
+
items = wl_match[1]
|
48
|
+
filename_matches = items.scan(/#{REGEX_LINK_LEFT}#{REGEX_FILENAME}#{REGEX_LINK_RIGHT}/i)
|
49
|
+
filename_matches.each do |match|
|
50
|
+
match.each do |fname|
|
51
|
+
wikilink_block.add_item(fname)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
# replace text
|
55
|
+
doc_content.gsub!(wikilink_block.md_regex, "\n")
|
56
|
+
@wikilink_blocks << wikilink_block
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse_inlines(doc_filename, doc_content)
|
62
|
+
inline_matches = doc_content.scan(REGEX_WIKI_LINK_INLINES)
|
63
|
+
if !inline_matches.nil? && inline_matches.size != 0
|
64
|
+
inline_matches.each do |wl_match|
|
65
|
+
@wikilink_inlines << WikiLinkInline.new(
|
66
|
+
@doc_manager,
|
67
|
+
doc_filename,
|
68
|
+
wl_match[0],
|
69
|
+
wl_match[1],
|
70
|
+
wl_match[2],
|
71
|
+
wl_match[3],
|
72
|
+
wl_match[4],
|
73
|
+
wl_match[5],
|
74
|
+
)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
# replace text
|
78
|
+
return if @wikilink_inlines.nil?
|
79
|
+
self.sort_typed_first
|
80
|
+
@wikilink_inlines.each do |wikilink|
|
81
|
+
doc_content.gsub!(
|
82
|
+
wikilink.md_regex,
|
83
|
+
self.build_html(wikilink)
|
84
|
+
)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# building/converting
|
89
|
+
|
90
|
+
def build_html_embed(title, content, url)
|
91
|
+
# multi-line for readability
|
92
|
+
return [
|
93
|
+
"<div class=\"#{$wiki_conf.css_name("embed_wrapper")}\">",
|
94
|
+
"<div class=\"#{$wiki_conf.css_name("embed_title")}\">",
|
95
|
+
"#{title}",
|
96
|
+
"</div>",
|
97
|
+
"<div class=\"#{$wiki_conf.css_name("embed_content")}\">",
|
98
|
+
"#{@markdown_converter.convert(content)}",
|
99
|
+
"</div>",
|
100
|
+
"<a class=\"#{$wiki_conf.css_name("embed_wiki_link")}\" href=\"#{url}\"></a>",
|
101
|
+
"</div>",
|
102
|
+
].join("\n").gsub!("\n", "")
|
103
|
+
end
|
104
|
+
|
105
|
+
def build_html_img_embed(static_doc, is_svg=false)
|
106
|
+
svg_content = ""
|
107
|
+
if is_svg
|
108
|
+
File.open(static_doc.path, "r") do |svg_img|
|
109
|
+
svg_content = svg_img.read
|
110
|
+
end
|
111
|
+
return "<p><span class=\"#{$wiki_conf.css_name("embed_image_wrapper")}\">#{svg_content}</span></p>"
|
112
|
+
else
|
113
|
+
return "<p><span class=\"#{$wiki_conf.css_name("embed_image_wrapper")}\"><img class=\"#{$wiki_conf.css_name("embed_image")}\" src=\"#{relative_url(static_doc.relative_path)}\"></span></p>"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def build_html(wikilink)
|
118
|
+
if !wikilink.is_valid?
|
119
|
+
return '<span class="' + $wiki_conf.css_name("invalid_wiki") + '">' + wikilink.md_str + '</span>'
|
120
|
+
end
|
121
|
+
# image processing
|
122
|
+
if wikilink.embedded? && wikilink.is_img?
|
123
|
+
return build_html_img_embed(wikilink.linked_img, is_svg=wikilink.is_img_svg?)
|
124
|
+
end
|
125
|
+
# markdown file processing
|
126
|
+
linked_doc = wikilink.linked_doc
|
127
|
+
link_type_txt = wikilink.is_typed? ? " #{$wiki_conf.css_name("typed")} #{wikilink.link_type}" : ""
|
128
|
+
|
129
|
+
inner_txt = wikilink.label_txt if wikilink.labelled?
|
130
|
+
lnk_doc_rel_url = relative_url(linked_doc.url)
|
131
|
+
|
132
|
+
if (wikilink.level == "file")
|
133
|
+
inner_txt = "#{linked_doc['title'].downcase}" if inner_txt.nil?
|
134
|
+
return build_html_embed(
|
135
|
+
linked_doc['title'],
|
136
|
+
linked_doc.content,
|
137
|
+
lnk_doc_rel_url
|
138
|
+
) if wikilink.embedded?
|
139
|
+
elsif (wikilink.level == "header")
|
140
|
+
# from: https://github.com/jekyll/jekyll/blob/6855200ebda6c0e33f487da69e4e02ec3d8286b7/Rakefile#L74
|
141
|
+
lnk_doc_rel_url += "\#" + Jekyll::Utils.slugify(wikilink.header_txt)
|
142
|
+
inner_txt = "#{linked_doc['title'].downcase} > #{wikilink.header_txt.downcase}" if inner_txt.nil?
|
143
|
+
elsif (wikilink.level == "block")
|
144
|
+
lnk_doc_rel_url += "\#" + wikilink.block_id
|
145
|
+
inner_txt = "#{linked_doc['title'].downcase} > ^#{wikilink.block_id}" if inner_txt.nil?
|
146
|
+
else
|
147
|
+
Jekyll.logger.error("Jekyll-Wikilinks: Invalid wikilink level")
|
148
|
+
end
|
149
|
+
return '<a class="' + $wiki_conf.css_name("wiki") + link_type_txt + '" href="' + lnk_doc_rel_url + '">' + inner_txt + '</a>'
|
150
|
+
end
|
151
|
+
|
152
|
+
# helpers
|
153
|
+
|
154
|
+
def sort_typed_first
|
155
|
+
# sorting inline wikilinks is necessary so when wikilinks are replaced,
|
156
|
+
# longer strings are replaced first so as not to accidentally overwrite
|
157
|
+
# substrings
|
158
|
+
# (this is especially likely if there is a matching wikilink that
|
159
|
+
# appears as both untyped and typed in a document)
|
160
|
+
temp = @wikilink_inlines.dup
|
161
|
+
@wikilink_inlines.clear()
|
162
|
+
typed_wikilinks = temp.select { |wl| wl.is_typed? }
|
163
|
+
untyped_wikilinks = temp.select { |wl| !wl.is_typed? }
|
164
|
+
@wikilink_inlines = typed_wikilinks.concat(untyped_wikilinks)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# regex.rb
|
2
|
+
# regex constants defining supported file types and valid names for files, variables, or text
|
3
|
+
#
|
4
|
+
|
5
|
+
module Jekyll
|
6
|
+
module WikiLinks
|
7
|
+
# <regex_variables> only work with 'match' function, not with 'scan' function. :/
|
8
|
+
# oh well...they are there for easier debugging...
|
9
|
+
|
10
|
+
# supported image formats
|
11
|
+
# from: https://docs.github.com/en/github/managing-files-in-a-repository/working-with-non-code-files/rendering-and-diffing-images
|
12
|
+
SUPPORTED_IMG_FORMATS = Set.new(['.png', '.jpg', '.gif', '.psd', '.svg'])
|
13
|
+
|
14
|
+
# wikilink constants
|
15
|
+
REGEX_LINK_LEFT = /\[\[/
|
16
|
+
REGEX_LINK_RIGHT = /\]\]/
|
17
|
+
REGEX_LINK_EMBED = /(?<embed>\!)/
|
18
|
+
REGEX_LINK_TYPE = /\s*::\s*/
|
19
|
+
REGEX_LINK_HEADER = /\#/
|
20
|
+
REGEX_LINK_BLOCK = /\#\^/
|
21
|
+
REGEX_LINK_LABEL = /\|/
|
22
|
+
|
23
|
+
# wikitext usable char requirements
|
24
|
+
REGEX_LINK_TYPE_CHARS = /[^\n\s\!\#\^\|\]]+/i
|
25
|
+
REGEX_FILENAME_CHARS = /[^\\\/:\#\^\|\[\]]+/i
|
26
|
+
REGEX_HEADER_CHARS = /[^\!\#\^\|\[\]]+/i
|
27
|
+
REGEX_BLOCK_ID_CHARS = /[^\\\/:\!\#\^\|\[\]^\n]+/i
|
28
|
+
REGEX_LABEL_CHARS = /(.+?)(?=\]{2}[^\]])/i
|
29
|
+
|
30
|
+
# capture groups
|
31
|
+
REGEX_LINK_TYPE_TXT = /(?<link-type-txt>#{REGEX_LINK_TYPE_CHARS})/i
|
32
|
+
REGEX_FILENAME = /(?<filename>#{REGEX_FILENAME_CHARS})/i
|
33
|
+
REGEX_HEADER_TXT = /(?<header-txt>#{REGEX_HEADER_CHARS})/i
|
34
|
+
REGEX_BLOCK_ID_TXT = /(?<block-id>#{REGEX_BLOCK_ID_CHARS})/i
|
35
|
+
REGEX_LABEL_TXT = /(?<label-txt>#{REGEX_LABEL_CHARS})/i
|
36
|
+
|
37
|
+
# target markdown text (headers, lists, and blocks)
|
38
|
+
## kramdown regexes
|
39
|
+
### atx header: https://github.com/gettalong/kramdown/blob/master/lib/kramdown/parser/kramdown/header.rb#L29
|
40
|
+
REGEX_ATX_HEADER = /^\#{1,6}[\t ]*([^ \t].*)\n/i
|
41
|
+
### setext header: https://github.com/gettalong/kramdown/blob/master/lib/kramdown/parser/kramdown/header.rb#L17
|
42
|
+
REGEX_SETEXT_HEADER = /^\s{0,3}([^ \t].*)\n[-=][-=]*[ \t\r\f\v]*\n/i
|
43
|
+
## list item: https://github.com/gettalong/kramdown/blob/master/lib/kramdown/parser/kramdown/list.rb#L49
|
44
|
+
REGEX_BULLET = /(?<bullet>[+*-])/i
|
45
|
+
## markdown-style block-reference
|
46
|
+
REGEX_BLOCK = /.*\s\^#{REGEX_BLOCK_ID_TXT}/i
|
47
|
+
|
48
|
+
# wikilinks
|
49
|
+
|
50
|
+
## inline
|
51
|
+
REGEX_WIKI_LINK_INLINES = %r{ # capture indeces
|
52
|
+
(#{REGEX_LINK_EMBED})? # 0
|
53
|
+
(#{REGEX_LINK_TYPE_TXT}#{REGEX_LINK_TYPE})? # 1
|
54
|
+
#{REGEX_LINK_LEFT}
|
55
|
+
#{REGEX_FILENAME} # 2
|
56
|
+
(#{REGEX_LINK_HEADER}#{REGEX_HEADER_TXT})? # 3
|
57
|
+
(#{REGEX_LINK_BLOCK}#{REGEX_BLOCK_ID_TXT})? # 4
|
58
|
+
(#{REGEX_LINK_LABEL}#{REGEX_LABEL_TXT})? # 5
|
59
|
+
#{REGEX_LINK_RIGHT}
|
60
|
+
}x
|
61
|
+
|
62
|
+
## block
|
63
|
+
### single
|
64
|
+
REGEX_SINGLE = /#{REGEX_LINK_LEFT}#{REGEX_FILENAME_CHARS}#{REGEX_LINK_RIGHT}/i
|
65
|
+
### list (comma is responsible for catching the single case)
|
66
|
+
REGEX_LIST_COMMA = /((?:\s*#{REGEX_SINGLE}\s*)(?:,\s*#{REGEX_SINGLE}\s*)*)/i
|
67
|
+
REGEX_LIST_MKDN = /((?<=\n)\s{0,3}#{REGEX_BULLET}\s#{REGEX_SINGLE}\s*)+/i # (see REGEX_LIST_ITEM)
|
68
|
+
### process
|
69
|
+
REGEX_BLOCK_TYPES = /((?<!\n)(?:#{REGEX_LIST_COMMA})|#{REGEX_LIST_MKDN})/i
|
70
|
+
REGEX_WIKI_LINK_BLOCKS = /^\s{0,3}#{REGEX_LINK_TYPE_TXT}#{REGEX_LINK_TYPE}(?:\s*|\G)(?<items>#{REGEX_BLOCK_TYPES})\n/i
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,278 @@
|
|
1
|
+
# wiki data structures
|
2
|
+
require_relative "regex"
|
3
|
+
|
4
|
+
module Jekyll
|
5
|
+
module WikiLinks
|
6
|
+
|
7
|
+
# wikilink classes know everything about the original markdown syntax and its semantic meaning
|
8
|
+
|
9
|
+
class WikiLinkBlock
|
10
|
+
attr_accessor :link_type, :filenames
|
11
|
+
|
12
|
+
# parameters ordered by appearance in regex
|
13
|
+
def initialize(doc_mngr, context_filename, link_type, bullet_type=nil)
|
14
|
+
@doc_mngr ||= doc_mngr
|
15
|
+
@context_filename ||= context_filename
|
16
|
+
@link_type ||= link_type
|
17
|
+
@bullet_type ||= bullet_type
|
18
|
+
@filenames = []
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_item(filename)
|
22
|
+
Jekyll.logger.error("Jekyll-Wikilinks: 'filename' required") if filename.nil? || filename.empty?
|
23
|
+
@filenames << filename
|
24
|
+
end
|
25
|
+
|
26
|
+
# data
|
27
|
+
|
28
|
+
def md_regex
|
29
|
+
if !is_typed? || !has_filenames?
|
30
|
+
Jekyll.logger.error("Jekyll-Wikilinks: WikiLinkBlock.md_regex error -- type: #{@link_type}, fnames: #{@filenames.inspect}, for: #{@context_filename}")
|
31
|
+
end
|
32
|
+
# comma (including singles)
|
33
|
+
if @bullet_type.nil?
|
34
|
+
link_type = /#{@link_type}#{REGEX_LINK_TYPE}/i
|
35
|
+
tmp_filenames = @filenames.dup
|
36
|
+
first_filename = /\s*#{REGEX_LINK_LEFT}#{tmp_filenames.shift()}#{REGEX_LINK_RIGHT}\s*/i
|
37
|
+
filename_strs = tmp_filenames.map { |f| /,\s*#{REGEX_LINK_LEFT}#{f}#{REGEX_LINK_RIGHT}\s*/i }
|
38
|
+
md_regex = /#{link_type}#{first_filename}#{filename_strs.join('')}\n/i
|
39
|
+
# mkdn
|
40
|
+
elsif !@bullet_type.match(REGEX_BULLET).nil?
|
41
|
+
link_type = /#{@link_type}#{REGEX_LINK_TYPE}\n/i
|
42
|
+
filename_strs = @filenames.map { |f| /\s{0,3}#{Regexp.escape(@bullet_type)}\s#{REGEX_LINK_LEFT}#{f}#{REGEX_LINK_RIGHT}\n/i }
|
43
|
+
md_regex = /#{link_type}#{filename_strs.join("")}/i
|
44
|
+
else
|
45
|
+
Jekyll.logger.error("Jekyll-Wikilinks: WikiLinkBlock.bullet_type error: #{@bullet_type}")
|
46
|
+
end
|
47
|
+
return md_regex
|
48
|
+
end
|
49
|
+
|
50
|
+
def md_str
|
51
|
+
if !is_typed? || !has_filenames?
|
52
|
+
Jekyll.logger.error("Jekyll-Wikilinks: WikiLinkBlockList.md_str error -- type: #{@link_type}, fnames: #{@filenames.inspect}, for: #{@context_filename}")
|
53
|
+
end
|
54
|
+
# comma (including singles)
|
55
|
+
if @bullet_type.nil?
|
56
|
+
link_type = "#{@link_type}::"
|
57
|
+
filename_strs = @filenames.map { |f| "\[\[#{f}\]\]," }
|
58
|
+
md_str = (link_type + filename_strs.join('')).delete_suffix(",")
|
59
|
+
# mkdn
|
60
|
+
elsif !@bullet_type.match(REGEX_BULLET).nil?
|
61
|
+
link_type = "#{@link_type}::\n"
|
62
|
+
filename_strs = @filenames.map { |f| li[0] + " \[\[#{li[1]}\]\]\n" }
|
63
|
+
md_str = link_type + filename_strs.join('')
|
64
|
+
else
|
65
|
+
Jekyll.logger.error("Jekyll-Wikilinks: 'bullet_type' invalid: #{@bullet_type}")
|
66
|
+
end
|
67
|
+
return md_str
|
68
|
+
end
|
69
|
+
|
70
|
+
def urls
|
71
|
+
# return @filenames.map { |f| @doc_mngr.get_doc_by_fname(f) }
|
72
|
+
urls = []
|
73
|
+
@filenames.each do |f|
|
74
|
+
doc = @doc_mngr.get_doc_by_fname(f)
|
75
|
+
urls << doc.url if !doc.nil?
|
76
|
+
end
|
77
|
+
return urls
|
78
|
+
end
|
79
|
+
|
80
|
+
# 'fm' -> frontmatter
|
81
|
+
|
82
|
+
def context_fm_data
|
83
|
+
return {
|
84
|
+
'type' => @link_type,
|
85
|
+
'urls' => [self.context_doc.url],
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def linked_fm_data
|
90
|
+
return {
|
91
|
+
'type' => @link_type,
|
92
|
+
'urls' => self.urls,
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
def context_doc
|
97
|
+
return @doc_mngr.get_doc_by_fname(@context_filename)
|
98
|
+
end
|
99
|
+
|
100
|
+
def linked_docs
|
101
|
+
docs = []
|
102
|
+
@filenames.each do |f|
|
103
|
+
doc = @doc_mngr.get_doc_by_fname(f)
|
104
|
+
docs << doc if !doc.nil?
|
105
|
+
end
|
106
|
+
return docs
|
107
|
+
end
|
108
|
+
|
109
|
+
# descriptor methods
|
110
|
+
|
111
|
+
def has_filenames?
|
112
|
+
return !@filenames.nil? && !@filenames.empty?
|
113
|
+
end
|
114
|
+
|
115
|
+
def is_typed?
|
116
|
+
return !@link_type.nil? && !@link_type.empty?
|
117
|
+
end
|
118
|
+
|
119
|
+
# validation methods
|
120
|
+
|
121
|
+
def is_valid?
|
122
|
+
return false if !is_typed?
|
123
|
+
return false if !has_filenames?
|
124
|
+
@filenames.each do |f|
|
125
|
+
return false if !@doc_mngr.file_exists?(f)
|
126
|
+
end
|
127
|
+
return true
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class WikiLinkInline
|
132
|
+
attr_accessor :context_filename, :embed, :link_type, :filename, :header_txt, :block_id, :label_txt
|
133
|
+
|
134
|
+
FILENAME = "filename"
|
135
|
+
HEADER_TXT = "header_txt"
|
136
|
+
BLOCK_ID = "block_id"
|
137
|
+
|
138
|
+
# parameters ordered by appearance in regex
|
139
|
+
def initialize(doc_mngr, context_filename, embed, link_type, filename, header_txt, block_id, label_txt)
|
140
|
+
@doc_mngr ||= doc_mngr
|
141
|
+
@context_filename ||= context_filename
|
142
|
+
@embed ||= embed
|
143
|
+
@link_type ||= link_type
|
144
|
+
@filename ||= filename
|
145
|
+
@header_txt ||= header_txt
|
146
|
+
@block_id ||= block_id
|
147
|
+
@label_txt ||= label_txt
|
148
|
+
end
|
149
|
+
|
150
|
+
# escape square brackets if they appear in label text
|
151
|
+
def label_txt
|
152
|
+
return @label_txt.sub("[", "\\[").sub("]", "\\]")
|
153
|
+
end
|
154
|
+
|
155
|
+
# data
|
156
|
+
|
157
|
+
def md_regex
|
158
|
+
regex_embed = embedded? ? REGEX_LINK_EMBED : %r{}
|
159
|
+
regex_link_type = is_typed? ? %r{#{@link_type}#{REGEX_LINK_TYPE}} : %r{}
|
160
|
+
filename = described?(FILENAME) ? @filename : ""
|
161
|
+
if described?(HEADER_TXT)
|
162
|
+
header = %r{#{REGEX_LINK_HEADER}#{@header_txt}}
|
163
|
+
block = %r{}
|
164
|
+
elsif described?(BLOCK_ID)
|
165
|
+
header = %r{}
|
166
|
+
block = %r{#{REGEX_LINK_BLOCK}#{@block_id}}
|
167
|
+
elsif !described?(FILENAME)
|
168
|
+
Jekyll.logger.error("Jekyll-Wikilinks: WikiLinkInline.md_regex error")
|
169
|
+
end
|
170
|
+
label_ = labelled? ? %r{#{REGEX_LINK_LABEL}#{label_txt}} : %r{}
|
171
|
+
return %r{#{regex_embed}#{regex_link_type}#{REGEX_LINK_LEFT}#{filename}#{header}#{block}#{label_}#{REGEX_LINK_RIGHT}}
|
172
|
+
end
|
173
|
+
|
174
|
+
def md_str
|
175
|
+
embed = embedded? ? "!" : ""
|
176
|
+
link_type = is_typed? ? "#{@link_type}::" : ""
|
177
|
+
filename = described?(FILENAME) ? @filename : ""
|
178
|
+
if described?(HEADER_TXT)
|
179
|
+
header = "\##{@header_txt}"
|
180
|
+
block = ""
|
181
|
+
elsif described?(BLOCK_ID)
|
182
|
+
header = ""
|
183
|
+
block = "\#\^#{@block_id}"
|
184
|
+
elsif !described?(FILENAME)
|
185
|
+
Jekyll.logger.error("Jekyll-Wikilinks: WikiLinkInline.md_str error")
|
186
|
+
end
|
187
|
+
label_ = labelled? ? "\|#{@label_txt}" : ""
|
188
|
+
return "#{embed}#{link_type}\[\[#{filename}#{header}#{block}#{label_}\]\]"
|
189
|
+
end
|
190
|
+
|
191
|
+
# 'fm' -> frontmatter
|
192
|
+
|
193
|
+
def context_fm_data
|
194
|
+
return {
|
195
|
+
'type' => @link_type,
|
196
|
+
'url' => self.context_doc.url,
|
197
|
+
}
|
198
|
+
end
|
199
|
+
|
200
|
+
def linked_fm_data
|
201
|
+
return {
|
202
|
+
'type' => @link_type,
|
203
|
+
'url' => self.linked_doc.url,
|
204
|
+
}
|
205
|
+
end
|
206
|
+
|
207
|
+
def context_doc
|
208
|
+
return @doc_mngr.get_doc_by_fname(@context_filename)
|
209
|
+
end
|
210
|
+
|
211
|
+
def linked_doc
|
212
|
+
return @doc_mngr.get_doc_by_fname(@filename)
|
213
|
+
end
|
214
|
+
|
215
|
+
def linked_img
|
216
|
+
return @doc_mngr.get_image_by_fname(@filename) if self.is_img?
|
217
|
+
return nil
|
218
|
+
end
|
219
|
+
|
220
|
+
# descriptor methods
|
221
|
+
|
222
|
+
# def describe
|
223
|
+
# return {
|
224
|
+
# 'level' => level,
|
225
|
+
# 'labelled' => labelled?,
|
226
|
+
# 'embedded' => embedded?,
|
227
|
+
# 'typed_link' => is_typed?,
|
228
|
+
# }
|
229
|
+
# end
|
230
|
+
|
231
|
+
def labelled?
|
232
|
+
return !@label_txt.nil? && !@label_txt.empty?
|
233
|
+
end
|
234
|
+
|
235
|
+
def is_typed?
|
236
|
+
return !@link_type.nil? && !@link_type.empty?
|
237
|
+
end
|
238
|
+
|
239
|
+
def embedded?
|
240
|
+
return !@embed.nil? && @embed == "!"
|
241
|
+
end
|
242
|
+
|
243
|
+
def is_img?
|
244
|
+
# github supported image formats: https://docs.github.com/en/github/managing-files-in-a-repository/working-with-non-code-files/rendering-and-diffing-images
|
245
|
+
return SUPPORTED_IMG_FORMATS.any?{ |ext| ext == File.extname(@filename).downcase }
|
246
|
+
end
|
247
|
+
|
248
|
+
def is_img_svg?
|
249
|
+
return File.extname(@filename).downcase == ".svg"
|
250
|
+
end
|
251
|
+
|
252
|
+
# this method helps to make the 'WikiLinkInline.level' code read like a clean truth table.
|
253
|
+
def described?(chunk)
|
254
|
+
return (!@filename.nil? && !@filename.empty?) if chunk == FILENAME
|
255
|
+
return (!@header_txt.nil? && !@header_txt.empty?) if chunk == HEADER_TXT
|
256
|
+
return (!@block_id.nil? && !@block_id.empty?) if chunk == BLOCK_ID
|
257
|
+
Jekyll.logger.error("Jekyll-Wikilinks: There is no link level '#{chunk}' in the WikiLink Class")
|
258
|
+
end
|
259
|
+
|
260
|
+
def level
|
261
|
+
return "file" if described?(FILENAME) && !described?(HEADER_TXT) && !described?(BLOCK_ID)
|
262
|
+
return "header" if described?(FILENAME) && described?(HEADER_TXT) && !described?(BLOCK_ID)
|
263
|
+
return "block" if described?(FILENAME) && !described?(HEADER_TXT) && described?(BLOCK_ID)
|
264
|
+
return "invalid"
|
265
|
+
end
|
266
|
+
|
267
|
+
# validation methods
|
268
|
+
|
269
|
+
def is_valid?
|
270
|
+
return false if !@doc_mngr.file_exists?(@filename)
|
271
|
+
return false if (self.level == "header") && !@doc_mngr.doc_has_header?(self.linked_doc, @header_txt)
|
272
|
+
return false if (self.level == "block") && !@doc_mngr.doc_has_block_id?(self.linked_doc, @block_id)
|
273
|
+
return true
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
end
|
278
|
+
end
|