markita 5.0.241001 → 6.0.250327
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/README.md +28 -15
- data/bin/markita +16 -19
- data/lib/markita/base.rb +38 -31
- data/lib/markita/config.rb +27 -18
- data/lib/markita/html.rb +35 -20
- data/lib/markita/markdown/attributes.rb +23 -0
- data/lib/markita/markdown/blockquote.rb +41 -0
- data/lib/markita/markdown/code.rb +44 -0
- data/lib/markita/markdown/code_block.rb +29 -0
- data/lib/markita/markdown/definitions.rb +42 -0
- data/lib/markita/markdown/embed.rb +63 -0
- data/lib/markita/markdown/empty.rb +22 -0
- data/lib/markita/markdown/fold.rb +39 -0
- data/lib/markita/markdown/footnotes.rb +28 -0
- data/lib/markita/markdown/form.rb +125 -0
- data/lib/markita/markdown/heading.rb +33 -0
- data/lib/markita/markdown/horizontal_rule.rb +25 -0
- data/lib/markita/markdown/image.rb +60 -0
- data/lib/markita/markdown/inline.rb +123 -0
- data/lib/markita/markdown/list.rb +65 -0
- data/lib/markita/markdown/markup.rb +23 -0
- data/lib/markita/markdown/script.rb +28 -0
- data/lib/markita/markdown/split.rb +38 -0
- data/lib/markita/markdown/table.rb +52 -0
- data/lib/markita/markdown.rb +51 -475
- data/lib/markita/plug/about.rb +28 -17
- data/lib/markita/plug/favicon.rb +14 -10
- data/lib/markita/plug/highlight.rb +17 -12
- data/lib/markita/plug/login.rb +35 -28
- data/lib/markita/plug/navigation.rb +4 -1
- data/lib/markita/plug/plugs.rb +7 -1
- data/lib/markita/plug/readme.rb +8 -4
- data/lib/markita/preprocess.rb +52 -23
- data/lib/markita/refinement.rb +21 -0
- data/lib/markita/requires.rb +29 -0
- data/lib/markita.rb +15 -25
- metadata +51 -135
data/lib/markita/markdown.rb
CHANGED
@@ -1,498 +1,74 @@
|
|
1
|
-
|
2
|
-
class Markdown
|
3
|
-
ROUGE = Rouge::Formatters::HTML.new
|
4
|
-
PARSERS = []
|
5
|
-
|
6
|
-
def initialize(title)
|
7
|
-
@title = title
|
8
|
-
@line=@html=@file=nil
|
9
|
-
@metadata,@attributes = {},[]
|
10
|
-
end
|
11
|
-
|
12
|
-
def start
|
13
|
-
@html << HTML.header(@title)
|
14
|
-
@line = HTML.navigation
|
15
|
-
end
|
16
|
-
|
17
|
-
def finish
|
18
|
-
if (title=@metadata['Title'])
|
19
|
-
@html << %(<script> document.title = "#{title}" </script>\n)
|
20
|
-
end
|
21
|
-
@html << HTML.footer
|
22
|
-
@line = nil
|
23
|
-
end
|
24
|
-
|
25
|
-
def init(fh)
|
26
|
-
@file,@html = Preprocess.new(fh),''
|
27
|
-
end
|
28
|
-
|
29
|
-
def parse(fh)
|
30
|
-
init(fh)
|
31
|
-
start
|
32
|
-
PARSERS.detect{method(_1).call} or default while @line
|
33
|
-
finish
|
34
|
-
end
|
35
|
-
|
36
|
-
def default
|
37
|
-
# Defaults to paragraph
|
38
|
-
# Let html take the original @html object and set @html to ''
|
39
|
-
html,@html = @html,''
|
40
|
-
html << "<p#{@attributes.shift}>\n"
|
41
|
-
loop do
|
42
|
-
html << inline(@line)
|
43
|
-
break if (@line=@file.gets).nil? || PARSERS.detect{method(_1).call}
|
44
|
-
end
|
45
|
-
html << "</p>\n"
|
46
|
-
html << @html
|
47
|
-
# Give back the original object to @html
|
48
|
-
@html = html
|
49
|
-
end
|
50
|
-
|
51
|
-
def markdown(string)
|
52
|
-
parse StringIO.new string
|
53
|
-
@html
|
54
|
-
end
|
55
|
-
|
56
|
-
def filepath(filepath)
|
57
|
-
File.open(filepath, 'r'){|fh| parse fh}
|
58
|
-
@html
|
59
|
-
end
|
1
|
+
# frozen_string_literal: true
|
60
2
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
I = ->(m){"<i>#{m[1]}</i>"}
|
69
|
-
|
70
|
-
Bx = /\*([^*]+)\*/
|
71
|
-
B = ->(m){"<b>#{m[1]}</b>"}
|
72
|
-
|
73
|
-
CODEx = /`([^`]+)`/
|
74
|
-
CODE = ->(m){"<code>#{m[1].gsub('<','<')}</code>"}
|
75
|
-
|
76
|
-
Ax = /\[([^\[\]]+)\]\(([^()]+)\)/
|
77
|
-
def anchor(m)
|
78
|
-
href = ((_=m[2]).match?(/^\d+$/) and @metadata[_] or _)
|
79
|
-
text = Markdown.tag(m[1], EMOJIx, EMOJI)
|
80
|
-
%(<a href="#{href}">#{text}</a>)
|
81
|
-
end
|
82
|
-
|
83
|
-
URLx = %r{(https?://[\w./&+?%-]+)}
|
84
|
-
URL = ->(m){%(<a href="#{m[1]}">#{m[1]}</a>)}
|
85
|
-
|
86
|
-
EMOJIx = /:(\w+):/
|
87
|
-
EMOJI = ->(m){(_=EMOJIS[m[1]])? "&#x#{_};" : m[0]}
|
88
|
-
|
89
|
-
FOOTNOTEx = /\[\^(\d+)\](:)?/
|
90
|
-
FOOTNOTE = lambda do |m|
|
91
|
-
if m[2]
|
92
|
-
%(<a id="fn:#{m[1]}" href="#fnref:#{m[1]}">#{m[1]}:</a>)
|
93
|
-
else
|
94
|
-
%(<a id="fnref:#{m[1]}" href="#fn:#{m[1]}"><sup>#{m[1]}</sup></a>)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
SUPERSCRIPTx = /\\\^\(([^()]+)\)/
|
99
|
-
SUPERSCRIPT = ->(m){"<sup>#{m[1]}</sup>"}
|
100
|
-
SUBSCRIPTx = /\\\(([^()]+)\)/
|
101
|
-
SUBSCRIPT = ->(m){"<sub>#{m[1]}</sub>"}
|
102
|
-
|
103
|
-
ENTITYx = /\\([<>*"~`_&;:\\])/
|
104
|
-
ENTITY = ->(m){"&##{m[1].ord};"}
|
105
|
-
|
106
|
-
def self.tag(entry, regx, m2string, &block)
|
107
|
-
if (m=regx.match entry)
|
108
|
-
string = ''
|
109
|
-
while m
|
110
|
-
pre_match = (block ? block.call(m.pre_match) : m.pre_match)
|
111
|
-
string << pre_match + m2string[m]
|
112
|
-
post_match = m.post_match
|
113
|
-
m = regx.match(post_match)
|
114
|
-
end
|
115
|
-
string << (block ? block.call(post_match) : post_match)
|
116
|
-
return string
|
117
|
-
end
|
118
|
-
block ? block.call(entry) : entry
|
119
|
-
end
|
120
|
-
|
121
|
-
def inline(entry)
|
122
|
-
entry = Markdown.tag(entry, ENTITYx, ENTITY)
|
123
|
-
string = Markdown.tag(entry, CODEx, CODE) do |entry|
|
124
|
-
Markdown.tag(entry, Ax, method(:anchor)) do |entry|
|
125
|
-
Markdown.tag(entry, URLx, URL) do |entry|
|
126
|
-
entry = Markdown.tag(entry, EMOJIx, EMOJI)
|
127
|
-
entry = Markdown.tag(entry, Bx, B)
|
128
|
-
entry = Markdown.tag(entry, Ix, I)
|
129
|
-
entry = Markdown.tag(entry, Sx, S)
|
130
|
-
entry = Markdown.tag(entry, Ux, U)
|
131
|
-
entry = Markdown.tag(entry, FOOTNOTEx, FOOTNOTE)
|
132
|
-
entry = Markdown.tag(entry, SUPERSCRIPTx, SUPERSCRIPT)
|
133
|
-
Markdown.tag(entry, SUBSCRIPTx, SUBSCRIPT)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
string.sub(/ ?[ \\]$/,'<br>')
|
138
|
-
end
|
3
|
+
# Markita top level namespace
|
4
|
+
module Markita
|
5
|
+
# The markdown parser.
|
6
|
+
# :reek:ClassVariable :reek:TooManyInstanceVariables
|
7
|
+
# rubocop:disable Style/ClassVars
|
8
|
+
class Markdown
|
9
|
+
ROUGE = Rouge::Formatters::HTML.new
|
139
10
|
|
140
|
-
|
141
|
-
EMPTY = /^$/
|
142
|
-
PARSERS << :empty
|
143
|
-
def empty
|
144
|
-
EMPTY.match?(@line) or return false
|
145
|
-
@line = @file.gets
|
146
|
-
true
|
147
|
-
end
|
11
|
+
@@parsers = []
|
148
12
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
level = md[:spaces].length
|
155
|
-
list = md[:bullet][0]=~/\d/ ? 'ol' : 'ul'
|
156
|
-
@html << "<#{list}#{@attributes.shift}>\n"
|
157
|
-
loop do
|
158
|
-
style = case md[:bullet][3]
|
159
|
-
when ' '
|
160
|
-
%q( style="list-style-type: '☐ '")
|
161
|
-
when 'x'
|
162
|
-
%q( style="list-style-type: '☑ '")
|
163
|
-
else
|
164
|
-
''
|
165
|
-
end
|
166
|
-
@html << " <li#{style}>#{inline(md[:text])}</li>\n"
|
167
|
-
if (md=(@line=@file.gets)&.match LIST) && level<md[:spaces].length
|
168
|
-
list(md)
|
169
|
-
md = @line&.match(LIST)
|
170
|
-
end
|
171
|
-
break unless md &&
|
172
|
-
(level == md[:spaces].length) &&
|
173
|
-
(list == (md[:bullet][0]=~/\d/ ? 'ol' : 'ul'))
|
13
|
+
def initialize(title)
|
14
|
+
@title = title
|
15
|
+
@line = @html = @line_getter = nil
|
16
|
+
@metadata = {}
|
17
|
+
@attributes = []
|
174
18
|
end
|
175
|
-
@html << "</#{list}>\n"
|
176
|
-
true
|
177
|
-
end
|
178
19
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
def definitions
|
183
|
-
md = DEFINITIONS.match(@line) or return false
|
184
|
-
@html << "<dl#{@attributes.shift}>\n"
|
185
|
-
while md
|
186
|
-
case md[1]
|
187
|
-
when /(.*): (.*)$/
|
188
|
-
@html << "<dt>#{inline $1.strip}</dt>\n"
|
189
|
-
@html << "<dd>#{inline $2.strip}</dd>\n"
|
190
|
-
when /(.*):$/
|
191
|
-
@html << "<dt>#{inline $1.strip}</dt>\n"
|
192
|
-
else
|
193
|
-
@html << "<dd>#{inline md[1].strip}</dd>\n"
|
20
|
+
def finish
|
21
|
+
if (title = @metadata['Title'])
|
22
|
+
@html << %(<script> document.title = "#{title}" </script>\n)
|
194
23
|
end
|
195
|
-
|
24
|
+
@html << Html.footer
|
25
|
+
@line = nil
|
196
26
|
end
|
197
|
-
@html << "</dl>\n"
|
198
|
-
true
|
199
|
-
end
|
200
27
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
md = HEADERS.match(@line) or return false
|
206
|
-
i,header = md[1].length,md[2]
|
207
|
-
id = header.gsub(/\([^()]*\)/,'').scan(/\w+/).join('+')
|
208
|
-
@html << %(<a id="#{id}">\n)
|
209
|
-
@html << " <h#{i}#{@attributes.shift}>#{inline(header)}</h#{i}>\n"
|
210
|
-
@html << "</a>\n"
|
211
|
-
@line = @file.gets
|
212
|
-
true
|
213
|
-
end
|
214
|
-
|
215
|
-
# Block-quote
|
216
|
-
BLOCKQS = /^( {0,3})> (.*)$/
|
217
|
-
PARSERS << :blockqs
|
218
|
-
def blockqs(md=nil)
|
219
|
-
md ||= BLOCKQS.match(@line) or return false
|
220
|
-
level = md[1].length
|
221
|
-
@html << "<blockquote#{@attributes.shift}>\n"
|
222
|
-
while md && level==md[1].length
|
223
|
-
@html << inline(md[2])
|
224
|
-
@html << "\n"
|
225
|
-
next unless (md=(@line=@file.gets)&.match BLOCKQS) && level<md[1].length
|
226
|
-
blockqs(md)
|
227
|
-
md = @line&.match(BLOCKQS)
|
28
|
+
# init(fh: String || File) -> void
|
29
|
+
def init(line_getter)
|
30
|
+
@line_getter = Preprocess.new(line_getter)
|
31
|
+
@html = String.new
|
228
32
|
end
|
229
|
-
@html << "</blockquote>\n"
|
230
|
-
true
|
231
|
-
end
|
232
|
-
|
233
|
-
# Code
|
234
|
-
CODES = /^[`]{3}\s*(\w+)?$/
|
235
|
-
PARSERS << :codes
|
236
|
-
def codes
|
237
|
-
md = CODES.match(@line) or return false
|
238
|
-
lang = Rouge::Lexer.find md[1]
|
239
|
-
klass = lang ? ' class="highlight"' : nil
|
240
|
-
@html << "<pre#{klass}#{@attributes.shift}><code>\n"
|
241
|
-
code = ''
|
242
|
-
code << @line while (@line=@file.gets) && !CODES.match?(@line)
|
243
|
-
@html << (lang ? ROUGE.format(lang.new.lex(code)) : code)
|
244
|
-
@html << "</code></pre>\n"
|
245
|
-
@line = @file.gets if @line # then it's code close and thus need next @line.
|
246
|
-
true
|
247
|
-
end
|
248
33
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
def preforms
|
253
|
-
md = PREFORMS.match(@line) or return false
|
254
|
-
@html << "<pre#{@attributes.shift}>\n"
|
255
|
-
while md
|
256
|
-
@html << md[1]
|
257
|
-
@html << "\n"
|
258
|
-
md = (@line=@file.gets)&.match PREFORMS
|
34
|
+
def start
|
35
|
+
@html << Html.header(@title)
|
36
|
+
@line = Html.navigation
|
259
37
|
end
|
260
|
-
@html << "</pre>\n"
|
261
|
-
true
|
262
|
-
end
|
263
38
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
@metadata[md[1]] = md[2]
|
270
|
-
md = (@line=@file.gets)&.match METADATAS
|
39
|
+
def parse(line_getter)
|
40
|
+
init(line_getter)
|
41
|
+
start
|
42
|
+
parsers_detect or default while @line
|
43
|
+
finish
|
271
44
|
end
|
272
|
-
true
|
273
|
-
end
|
274
45
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
def hrs
|
279
|
-
HRS.match? @line or return false
|
280
|
-
@line = @file.gets
|
281
|
-
if metadata
|
282
|
-
# Optional closing HRS
|
283
|
-
@line = @file.gets if @line&.match? HRS
|
284
|
-
else
|
285
|
-
# Display HR
|
286
|
-
@html << "<hr#{@attributes.shift}>\n"
|
46
|
+
def filepath(filepath)
|
47
|
+
File.open(filepath, 'r') { parse it }
|
48
|
+
@html
|
287
49
|
end
|
288
|
-
true
|
289
|
-
end
|
290
50
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
def tables
|
295
|
-
TABLES.match? @line or return false
|
296
|
-
@html << "<table#{@attributes.shift}>\n"
|
297
|
-
@html << "<thead#{@attributes.shift}><tr><th>"
|
298
|
-
@html << @line[1...-1].split('|').map{inline(_1.strip)}.join('</th><th>')
|
299
|
-
@html << "</th></tr></thead>\n"
|
300
|
-
align = []
|
301
|
-
while (@line=@file.gets)&.match? TABLES
|
302
|
-
@html << '<tr>'
|
303
|
-
@line[1...-1].split('|').each_with_index do |cell, i|
|
304
|
-
case cell
|
305
|
-
when /^\s*:-+:\s*$/
|
306
|
-
align[i] = ' align="center"'
|
307
|
-
@html << '<td><hr></td>'
|
308
|
-
when /^\s*-+:\s*$/
|
309
|
-
align[i] = ' align="right"'
|
310
|
-
@html << '<td><hr></td>'
|
311
|
-
when /^\s*:-+\s*$/
|
312
|
-
align[i] = ' align="left"'
|
313
|
-
@html << '<td><hr></td>'
|
314
|
-
else
|
315
|
-
@html << "<td#{align[i]}>#{inline(cell.strip)}</td>"
|
316
|
-
end
|
317
|
-
end
|
318
|
-
@html << "</tr>\n"
|
51
|
+
def markdown(string)
|
52
|
+
parse StringIO.new string
|
53
|
+
@html
|
319
54
|
end
|
320
|
-
@html << "</table>\n"
|
321
|
-
true
|
322
|
-
end
|
323
55
|
|
324
|
-
|
325
|
-
SPLITS = /^:?\|:?$/
|
326
|
-
PARSERS << :splits
|
327
|
-
def splits
|
328
|
-
SPLITS.match? @line or return false
|
329
|
-
case @line.chomp
|
330
|
-
when '|:'
|
331
|
-
@html << %(<table><tr><td#{@attributes.shift}>\n)
|
332
|
-
when '|'
|
333
|
-
@html << %(</td><td#{@attributes.shift}>\n)
|
334
|
-
when ':|:'
|
335
|
-
@html << %(</td></tr><tr><td#{@attributes.shift}>\n)
|
336
|
-
when ':|'
|
337
|
-
@html << %(</td></tr></table>\n)
|
338
|
-
end
|
339
|
-
@line = @file.gets
|
340
|
-
true
|
341
|
-
end
|
56
|
+
def parsers_detect = @@parsers.detect { method(it).call }
|
342
57
|
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
when /:$/
|
355
|
-
style = %( style="float:left;" )
|
356
|
-
when /^:/
|
357
|
-
style = %( style="float:right;" )
|
358
|
-
end
|
359
|
-
if /(\d+)x(\d+)/.match alt
|
360
|
-
style << %(width="#{$1}" height="#{$2}" )
|
361
|
-
end
|
362
|
-
@html << %(<a href="#{href}">\n) if href
|
363
|
-
@html <<
|
364
|
-
%(<img src="#{src}"#{style}alt="#{alt.strip}"#{@attributes.shift}>\n)
|
365
|
-
@html << %(</a>\n) if href
|
366
|
-
@line = @file.gets
|
367
|
-
true
|
368
|
-
end
|
369
|
-
|
370
|
-
# Embed text
|
371
|
-
EMBED_TEXTS = /^!> (#{PAGE_KEY}\.\w+)$/
|
372
|
-
PARSERS << :embed_texts
|
373
|
-
def embed_texts
|
374
|
-
md = EMBED_TEXTS.match(@line) or return false
|
375
|
-
if File.exist?(filename=File.join(ROOT, md[1]))
|
376
|
-
extension,lang = filename.split('.').last,nil
|
377
|
-
unless extension=='html'
|
378
|
-
lang = Rouge::Lexer.find(extension) unless extension=='txt'
|
379
|
-
klass = lang ? ' class="highlight"' : nil
|
380
|
-
@html << "<pre#{klass}#{@attributes.shift}>"
|
381
|
-
@html << '<code>' if lang
|
382
|
-
@html << "\n"
|
383
|
-
end
|
384
|
-
code = File.read(filename)
|
385
|
-
@html << (lang ? ROUGE.format(lang.new.lex(code)) : code)
|
386
|
-
unless extension=='html'
|
387
|
-
@html << '</code>' if lang
|
388
|
-
@html << '</pre>'
|
389
|
-
@html << "\n"
|
390
|
-
end
|
391
|
-
else
|
392
|
-
@html << @line
|
393
|
-
end
|
394
|
-
@line = @file.gets
|
395
|
-
true
|
396
|
-
end
|
397
|
-
|
398
|
-
# Footnotes
|
399
|
-
FOOTNOTES = /^\[\^\d+\]:/
|
400
|
-
PARSERS << :footnotes
|
401
|
-
def footnotes
|
402
|
-
md = FOOTNOTES.match(@line) or return false
|
403
|
-
@html << "<small>\n"
|
404
|
-
while md
|
405
|
-
@html << inline(@line.chomp)+"<br>\n"
|
406
|
-
md = (@line=@file.gets)&.match FOOTNOTES
|
407
|
-
end
|
408
|
-
@html << "</small>\n"
|
409
|
-
true
|
410
|
-
end
|
411
|
-
|
412
|
-
# Attributes
|
413
|
-
ATTRIBUTES = /^\{:( [^\{\}]+)\}/
|
414
|
-
PARSERS << :attributes
|
415
|
-
def attributes
|
416
|
-
md = ATTRIBUTES.match(@line) or return false
|
417
|
-
@attributes.push md[1]
|
418
|
-
@line = md.post_match
|
419
|
-
true
|
420
|
-
end
|
421
|
-
|
422
|
-
# Script
|
423
|
-
SCRIPT = /^<script/
|
424
|
-
PARSERS << :script
|
425
|
-
def script
|
426
|
-
SCRIPT.match(@line) or return false
|
427
|
-
@html << @line
|
428
|
-
while (@line=@file.gets)
|
429
|
-
@html << @line
|
430
|
-
break if %r{^</script>}.match?(@line)
|
58
|
+
# Defaults to paragraph
|
59
|
+
# :reek:DuplicateMethodCall :reek:TooManyStatements
|
60
|
+
def default
|
61
|
+
# Let html take the original @html String and set @html to String.new('')
|
62
|
+
html = @html
|
63
|
+
@html = String.new
|
64
|
+
html << "<p#{@attributes.shift}>\n"
|
65
|
+
html << inline(@line)
|
66
|
+
html << inline(@line) while line_gets && !parsers_detect
|
67
|
+
html << "</p>\n#{@html}"
|
68
|
+
@html = html # Give back the original String to @html
|
431
69
|
end
|
432
|
-
@line = @file.gets if @line
|
433
|
-
true
|
434
|
-
end
|
435
|
-
|
436
|
-
# Html
|
437
|
-
HTML_MARKUP = /^ {0,3}<.*>$/
|
438
|
-
PARSERS << :html_markup
|
439
|
-
def html_markup
|
440
|
-
HTML_MARKUP.match(@line) or return false
|
441
|
-
@html << @line
|
442
|
-
@line = @file.gets
|
443
|
-
true
|
444
|
-
end
|
445
70
|
|
446
|
-
|
447
|
-
FIELD = '(\w+:)?\[(\*)?(\w+)(=("[^"]+")(,"[^"]+")*)?\]'
|
448
|
-
FIELDS = Regexp.new FIELD
|
449
|
-
FORMS = Regexp.new "^!( #{FIELD})+"
|
450
|
-
PARSERS << :forms
|
451
|
-
def forms
|
452
|
-
md = FORMS.match(@line) or return false
|
453
|
-
fields,nl,submit = 0,false,nil
|
454
|
-
action = (_=/\(([^()]*)\)!?$/.match(@line))? %( action="#{_[1]}") : nil
|
455
|
-
method = @line.match?(/!$/) ? ' method="post"' : nil
|
456
|
-
@html << %(<form#{action}#{method}#{@attributes.shift}>\n)
|
457
|
-
while md
|
458
|
-
@html << " <br>\n" if nl
|
459
|
-
@line.scan(FIELDS).each do |field, pwd, name, value|
|
460
|
-
field &&= field[0...-1]
|
461
|
-
value &&= value[2...-1]
|
462
|
-
if field
|
463
|
-
type = pwd ? 'password' : 'text'
|
464
|
-
if value
|
465
|
-
if (values = value.split('","')).length > 1
|
466
|
-
@html << %(#{field}:<select name="#{name}">\n)
|
467
|
-
values.each do |value|
|
468
|
-
fields += 1
|
469
|
-
@html << %( <option value="#{value}">#{value}</option>\n)
|
470
|
-
end
|
471
|
-
@html << "</select>\n"
|
472
|
-
else
|
473
|
-
fields += 1
|
474
|
-
@html << %( #{field}:<input type="#{type}" name="#{name}")
|
475
|
-
@html << %( value="#{value}">\n)
|
476
|
-
end
|
477
|
-
else
|
478
|
-
fields += 1
|
479
|
-
@html << %( #{field}:<input type="#{type}" name="#{name}">\n)
|
480
|
-
end
|
481
|
-
elsif name=='submit'
|
482
|
-
submit = value
|
483
|
-
else
|
484
|
-
@html << %( <input type="hidden" name="#{name}" value="#{value}">\n)
|
485
|
-
end
|
486
|
-
end
|
487
|
-
md=(@line=@file.gets)&.match(FORMS) and nl=true
|
488
|
-
end
|
489
|
-
if submit || fields!=1
|
490
|
-
submit ||= 'Submit'
|
491
|
-
@html << " <br>\n" if nl
|
492
|
-
@html << %( <input type="submit" value="#{submit}">\n)
|
493
|
-
end
|
494
|
-
@html << %(</form>\n)
|
495
|
-
true
|
71
|
+
def line_gets = @line = @line_getter.gets
|
496
72
|
end
|
497
|
-
|
73
|
+
# rubocop:enable Style/ClassVars
|
498
74
|
end
|
data/lib/markita/plug/about.rb
CHANGED
@@ -1,33 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Markita namespace
|
1
4
|
module Markita
|
2
|
-
class
|
3
|
-
|
4
|
-
|
5
|
-
|
5
|
+
# Base class of the Sinatra Markita application
|
6
|
+
class Base
|
7
|
+
# About namespace to support the /about.html route
|
8
|
+
module About
|
9
|
+
ABOUT_TEXT = <<~TEXT.freeze
|
6
10
|
# [Markita](https://github.com/carlosjhr64/markita)
|
7
11
|
|
8
12
|
* VERSION: #{VERSION}
|
9
|
-
* ROOT: #{ROOT.sub(%r{^/home/\w+/},'~/')}
|
13
|
+
* ROOT: #{ROOT.sub(%r{^/home/\w+/}, '~/')}
|
10
14
|
* ARGV: #{ARGV.join(' ')}
|
11
15
|
* START_TIME: #{START_TIME}
|
12
16
|
|
13
17
|
## Plug.html routes:
|
14
18
|
|
15
19
|
TEXT
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
|
21
|
+
def self.plugs
|
22
|
+
Base.routes['GET'].each do |route|
|
23
|
+
path = route[0].to_s
|
24
|
+
next unless %r{^/\w+\.html$}.match? path
|
25
|
+
|
26
|
+
yield path, File.basename(path, '.*')
|
27
|
+
end
|
21
28
|
end
|
22
|
-
|
23
|
-
|
29
|
+
|
30
|
+
def self.page
|
31
|
+
text = ABOUT_TEXT.dup
|
32
|
+
plugs { |path, basename| text << "* [#{basename}](#{path})\n" }
|
33
|
+
if defined? Favicon && Favicon::ICO
|
34
|
+
text << "\n\n"
|
35
|
+
end
|
36
|
+
text
|
24
37
|
end
|
25
|
-
text
|
26
38
|
end
|
27
|
-
end
|
28
39
|
|
29
|
-
|
30
|
-
|
40
|
+
get '/about.html' do
|
41
|
+
Markdown.new('About').markdown About.page
|
42
|
+
end
|
31
43
|
end
|
32
44
|
end
|
33
|
-
end
|
data/lib/markita/plug/favicon.rb
CHANGED
@@ -1,15 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Markita namespace
|
1
4
|
module Markita
|
2
|
-
|
3
|
-
|
4
|
-
%(\n<link rel="icon" type="image/x-icon" href="/favicon.ico">)
|
5
|
+
Html.header_links <<
|
6
|
+
%(<link rel="icon" type="image/x-icon" href="/favicon.ico">\n)
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
8
|
+
# Base class of the Sinatra Markita application
|
9
|
+
class Base
|
10
|
+
module Favicon
|
11
|
+
ICO = File.read PATH['favicon.ico']
|
12
|
+
end
|
9
13
|
|
10
|
-
|
11
|
-
|
12
|
-
|
14
|
+
get '/favicon.ico' do
|
15
|
+
headers 'Content-Type' => 'image/x-icon'
|
16
|
+
Favicon::ICO
|
17
|
+
end
|
13
18
|
end
|
14
19
|
end
|
15
|
-
end
|
@@ -1,17 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Markita namespace
|
1
4
|
module Markita
|
2
|
-
|
3
|
-
|
4
|
-
%(\n<link rel="stylesheet" href="/highlight.css" type="text/css">)
|
5
|
+
Html.header_links <<
|
6
|
+
%(<link rel="stylesheet" href="/highlight.css" type="text/css">\n)
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
# Base class of the Sinatra Markita application
|
9
|
+
class Base
|
10
|
+
# Highlight namespace to support the /highlight.css route
|
11
|
+
module Highlight
|
12
|
+
theme = OPTIONS.theme || 'base16.light'
|
13
|
+
CSS = Rouge::Theme.find(theme)&.render(scope: '.highlight')
|
14
|
+
raise "Can't find Rouge Theme #{theme}" unless CSS
|
15
|
+
end
|
11
16
|
|
12
|
-
|
13
|
-
|
14
|
-
|
17
|
+
get '/highlight.css' do
|
18
|
+
headers 'Content-Type' => 'text/css'
|
19
|
+
Highlight::CSS
|
20
|
+
end
|
15
21
|
end
|
16
22
|
end
|
17
|
-
end
|