trac-wiki 0.1.12 → 0.2.16
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.
- data/.gitignore +2 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +26 -0
- data/lib/trac-wiki.rb +1 -0
- data/lib/trac-wiki/parser.rb +293 -153
- data/lib/trac-wiki/tree.rb +162 -0
- data/lib/trac-wiki/version.rb +1 -1
- data/test/parser_test.rb +99 -27
- data/test/tree_test.rb +35 -0
- metadata +21 -11
- checksums.yaml +0 -7
data/.gitignore
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
trac-wiki (0.2.12)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
bacon (1.2.0)
|
10
|
+
iconv (1.0.3)
|
11
|
+
mini_portile (0.5.2)
|
12
|
+
nokogiri (1.6.1)
|
13
|
+
mini_portile (~> 0.5.0)
|
14
|
+
rake (10.0.4)
|
15
|
+
sanitize (2.0.6)
|
16
|
+
nokogiri (>= 1.4.4)
|
17
|
+
|
18
|
+
PLATFORMS
|
19
|
+
ruby
|
20
|
+
|
21
|
+
DEPENDENCIES
|
22
|
+
bacon
|
23
|
+
iconv
|
24
|
+
rake
|
25
|
+
sanitize
|
26
|
+
trac-wiki!
|
data/lib/trac-wiki.rb
CHANGED
data/lib/trac-wiki/parser.rb
CHANGED
@@ -45,7 +45,7 @@ module TracWiki
|
|
45
45
|
attr_accessor :allowed_schemes
|
46
46
|
|
47
47
|
attr_accessor :headings
|
48
|
-
|
48
|
+
attr_writer :base
|
49
49
|
|
50
50
|
# Disable url escaping for local links
|
51
51
|
# Escaping: [[/Test]] --> %2FTest
|
@@ -61,6 +61,12 @@ module TracWiki
|
|
61
61
|
attr_writer :math
|
62
62
|
def math?; @math; end
|
63
63
|
|
64
|
+
# allow {{{! ... html ... }}}
|
65
|
+
# html will be sanitized
|
66
|
+
# {{{!\n html here \n}}}\n
|
67
|
+
attr_writer :raw_html
|
68
|
+
def raw_html?; @raw_html; end
|
69
|
+
|
64
70
|
attr_writer :edit_heading
|
65
71
|
def edit_heading?; @edit_heading; end
|
66
72
|
|
@@ -79,6 +85,12 @@ module TracWiki
|
|
79
85
|
|
80
86
|
# when id_from_heading, non ascii char are transliterated to ascii
|
81
87
|
attr_writer :id_translit
|
88
|
+
|
89
|
+
# string begins with macro
|
90
|
+
MACRO_BEG_REX = /\A\{\{ ( [\$]?\w+ | \#\w* ) /x
|
91
|
+
MACRO_BEG_INSIDE_REX = /(.*?)(?<!\{)\{\{ ( \$\w+ | \#\w* | \w+ ) /x
|
92
|
+
# find end of marcro or begin of inner macro
|
93
|
+
MACRO_END_REX = /\A(.*?) ( \}\} | \{\{ (\$\w+|\#\w*|\w+) )/mx
|
82
94
|
def id_translit?; @id_translit; end
|
83
95
|
|
84
96
|
# Create a new Parser instance.
|
@@ -87,9 +99,14 @@ module TracWiki
|
|
87
99
|
@anames = {}
|
88
100
|
@text = text
|
89
101
|
@no_escape = nil
|
102
|
+
@base = ''
|
90
103
|
options.each_pair {|k,v| send("#{k}=", v) }
|
104
|
+
@base += '/' if !@base.empty? && @base[-1] != '/'
|
91
105
|
end
|
92
106
|
|
107
|
+
# th(macroname) -> template_text
|
108
|
+
attr_writer :template_handler
|
109
|
+
|
93
110
|
@was_math = false
|
94
111
|
def was_math?; @was_math; end
|
95
112
|
|
@@ -103,7 +120,7 @@ module TracWiki
|
|
103
120
|
# parser.to_html
|
104
121
|
# #=> "<p><strong>Hello <em>World</em></strong></p>"
|
105
122
|
def to_html
|
106
|
-
@
|
123
|
+
@tree = TracWiki::Tree.new
|
107
124
|
@edit_heading_class = 'editheading'
|
108
125
|
@headings = [ {level: 0, sline: 1 } ]
|
109
126
|
@p = false
|
@@ -112,12 +129,13 @@ module TracWiki
|
|
112
129
|
@was_math = false
|
113
130
|
@line_no = 1
|
114
131
|
parse_block(@text)
|
115
|
-
@
|
132
|
+
@tree.to_html
|
116
133
|
end
|
117
134
|
|
118
135
|
def make_toc_html
|
119
|
-
@
|
136
|
+
@tree = TracWiki::Tree.new
|
120
137
|
parse_block(make_toc)
|
138
|
+
@tree.to_html
|
121
139
|
end
|
122
140
|
|
123
141
|
protected
|
@@ -130,7 +148,7 @@ module TracWiki
|
|
130
148
|
end
|
131
149
|
|
132
150
|
def self.escapeHTML(string)
|
133
|
-
string.gsub(
|
151
|
+
string.gsub(/&/, '&').gsub(/\"/, '"').gsub(/>/, '>').gsub(/</, '<')
|
134
152
|
end
|
135
153
|
|
136
154
|
# Escape any characters with special meaning in URLs using URL
|
@@ -139,16 +157,16 @@ module TracWiki
|
|
139
157
|
CGI::escape(string)
|
140
158
|
end
|
141
159
|
|
142
|
-
def start_tag(tag, args =
|
160
|
+
def start_tag(tag, args = {}, lindent = nil)
|
143
161
|
lindent = @stacki.last || -1 if lindent.nil?
|
144
162
|
|
145
163
|
@stack.push(tag)
|
146
164
|
@stacki.push(lindent)
|
147
165
|
|
148
166
|
if tag == 'strongem'
|
149
|
-
@
|
167
|
+
@tree.tag_beg(:strong).tag_beg(:em)
|
150
168
|
else
|
151
|
-
@
|
169
|
+
@tree.tag_beg(tag, args)
|
152
170
|
end
|
153
171
|
end
|
154
172
|
|
@@ -156,11 +174,11 @@ module TracWiki
|
|
156
174
|
tag = @stack.pop
|
157
175
|
tagi = @stacki.pop
|
158
176
|
if tag == 'strongem'
|
159
|
-
@
|
177
|
+
@tree.tag_end(:em).tag_end(:strong);
|
160
178
|
elsif tag == 'p'
|
161
|
-
@
|
179
|
+
@tree.tag_end(:p)
|
162
180
|
else
|
163
|
-
@
|
181
|
+
@tree.tag_end(tag)
|
164
182
|
end
|
165
183
|
end
|
166
184
|
|
@@ -169,7 +187,7 @@ module TracWiki
|
|
169
187
|
if @stack.last == tag
|
170
188
|
end_tag
|
171
189
|
else
|
172
|
-
@
|
190
|
+
@tree.add(match)
|
173
191
|
end
|
174
192
|
else
|
175
193
|
start_tag(tag)
|
@@ -183,7 +201,8 @@ module TracWiki
|
|
183
201
|
|
184
202
|
def start_paragraph
|
185
203
|
if @p
|
186
|
-
|
204
|
+
#FIXME: multiple space s
|
205
|
+
@tree.add_spc
|
187
206
|
else
|
188
207
|
end_paragraph
|
189
208
|
start_tag('p')
|
@@ -210,10 +229,10 @@ module TracWiki
|
|
210
229
|
# make_local_link("LocalLink") #=> "/LocalLink"
|
211
230
|
# make_local_link("Wikipedia:Bread") #=> "http://en.wikipedia.org/wiki/Bread"
|
212
231
|
def make_local_link(link) #:doc:
|
213
|
-
return link if no_escape?
|
232
|
+
return "#{@base}#{link}" if no_escape?
|
214
233
|
link, anch = link.split(/#/, 2)
|
215
|
-
return escape_url(link) if ! anch
|
216
|
-
"#{escape_url(link)}##{escape_url(anch)}"
|
234
|
+
return "#{@base}#{escape_url(link)}" if ! anch
|
235
|
+
"#{@base}#{escape_url(link)}##{escape_url(anch)}"
|
217
236
|
end
|
218
237
|
|
219
238
|
# Sanatize a direct url (e.g. http://wikipedia.org/). The default
|
@@ -252,13 +271,14 @@ module TracWiki
|
|
252
271
|
# markup, for example to add html additional attributes or
|
253
272
|
# to put divs around the imgs.
|
254
273
|
def make_image(uri, attrs='')
|
255
|
-
"<img src=\"#{make_explicit_link(uri)}\"#{make_image_attrs(attrs)}/>"
|
274
|
+
#"<img src=\"#{make_explicit_link(uri)}\"#{make_image_attrs(attrs)}/>"
|
275
|
+
@tree.tag(:img, make_image_attrs(uri, attrs))
|
256
276
|
end
|
257
277
|
|
258
|
-
def make_image_attrs(attrs)
|
259
|
-
|
260
|
-
a = {}
|
278
|
+
def make_image_attrs(uri, attrs)
|
279
|
+
a = {src: make_explicit_link(uri)}
|
261
280
|
style = []
|
281
|
+
attrs ||= ''
|
262
282
|
attrs.strip.split(/\s*,\s*/).each do |opt|
|
263
283
|
case opt
|
264
284
|
when /^\d+[^\d]*$/
|
@@ -277,28 +297,25 @@ module TracWiki
|
|
277
297
|
style.push($1 + ':' + escape_url($3))
|
278
298
|
end
|
279
299
|
end
|
280
|
-
a[
|
281
|
-
return
|
282
|
-
return
|
300
|
+
a[:style] = style.join(';') if ! style.empty?
|
301
|
+
return {} if a.empty?
|
302
|
+
return a;
|
283
303
|
end
|
284
304
|
|
285
305
|
def make_headline(level, text, aname)
|
286
|
-
ret = "<h#{level}"
|
287
|
-
if aname
|
288
|
-
ret += " id=\"#{ escape_html(aname) }\""
|
289
|
-
end
|
290
|
-
ret += ">" + escape_html(text)
|
291
306
|
|
307
|
+
hN = "h#{level}".to_sym
|
308
|
+
|
309
|
+
@tree.tag_beg(hN, { id: aname } )
|
310
|
+
parse_inline(text)
|
292
311
|
if edit_heading?
|
293
|
-
|
312
|
+
edit_heading_link(@headings.size - 1)
|
294
313
|
end
|
295
|
-
|
296
|
-
ret += "</h#{level}>"
|
297
|
-
ret
|
314
|
+
@tree.tag_end(hN)
|
298
315
|
end
|
299
316
|
|
300
317
|
def edit_heading_link(section)
|
301
|
-
|
318
|
+
@tree.tag(:a, { class: @edit_heading_class, href: "?edit=#{section}"}, "edit")
|
302
319
|
end
|
303
320
|
|
304
321
|
def make_explicit_link(link)
|
@@ -329,18 +346,18 @@ module TracWiki
|
|
329
346
|
when /\A(!)?((https?|ftps?):\/\/\S+?)(?=([\]\,.?!:;"'\)]+)?(\s|$))/
|
330
347
|
str = $'
|
331
348
|
if $1
|
332
|
-
@
|
349
|
+
@tree.add($2)
|
333
350
|
else
|
334
351
|
if uri = make_direct_link($2)
|
335
|
-
@
|
352
|
+
@tree.tag(:a, {href:uri}, $2)
|
336
353
|
else
|
337
|
-
@
|
354
|
+
@tree.add($&)
|
338
355
|
end
|
339
356
|
end
|
340
357
|
# [[Image(pic.jpg|tag)]]
|
341
358
|
when /\A\[\[Image\(([^,]*?)(,(.*?))?\)\]\]/ # image
|
342
359
|
str = $'
|
343
|
-
|
360
|
+
make_image($1, $3)
|
344
361
|
# [[link]]
|
345
362
|
# [ link1 | text2 ]
|
346
363
|
when /\A \[ \s* ([^\[|]*?) \s* (\|\s*(.*?))? \s* \] /mx
|
@@ -361,58 +378,55 @@ module TracWiki
|
|
361
378
|
def make_link(link, content, whole)
|
362
379
|
# specail "link" [[BR]]:
|
363
380
|
if link =~ /^br$/i
|
364
|
-
@
|
381
|
+
@tree.tag(:br)
|
365
382
|
return
|
366
383
|
end
|
367
384
|
uri = make_explicit_link(link)
|
368
385
|
if not uri
|
369
|
-
@
|
386
|
+
@tree.add(whole)
|
370
387
|
return
|
371
388
|
end
|
372
389
|
|
373
390
|
if no_link?
|
374
391
|
if uri !~ /^(ftp|https?):/
|
375
|
-
@
|
392
|
+
@tree.add(whole)
|
376
393
|
return
|
377
394
|
end
|
378
395
|
end
|
379
396
|
|
380
|
-
@
|
397
|
+
@tree.tag_beg(:a, {href:uri})
|
381
398
|
if content
|
382
399
|
until content.empty?
|
383
400
|
content = parse_inline_tag(content)
|
384
401
|
end
|
385
402
|
else
|
386
|
-
@
|
403
|
+
@tree.add(link)
|
387
404
|
end
|
388
|
-
@
|
405
|
+
@tree.tag_end(:a)
|
389
406
|
end
|
390
407
|
|
391
408
|
def parse_inline_tag(str)
|
392
409
|
case
|
393
410
|
when str =~ /\A\{\{\{(.*?\}*)\}\}\}/ # inline pre (tt)
|
394
|
-
@
|
411
|
+
@tree.tag(:tt, $1)
|
412
|
+
when str =~ MACRO_BEG_REX # macro {{
|
413
|
+
str, lines = parse_macro($1, $')
|
414
|
+
#print "MACRO.inline(#{$1})"
|
415
|
+
return str
|
395
416
|
when str =~ /\A`(.*?)`/ # inline pre (tt)
|
396
|
-
@
|
397
|
-
|
417
|
+
@tree.tag(:tt, $1)
|
398
418
|
when math? && str =~ /\A\$(.+?)\$/ # inline math (tt)
|
399
|
-
@
|
419
|
+
@tree.add("\\( #{$1} \\)")
|
420
|
+
#@tree.add("$#{$1}$")
|
421
|
+
#@tree.tag(:span, {class:'math'}, $1)
|
400
422
|
@was_math = true
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
# when /\A\{\{\s*(.*?)\s*(\|\s*(.*?)\s*)?\}\}/
|
406
|
-
# if uri = make_image_link($1)
|
407
|
-
# @out << make_image(uri, $3)
|
408
|
-
# else
|
409
|
-
# @out << escape_html($&)
|
410
|
-
# end # link
|
411
|
-
|
423
|
+
when str =~ /\A(\&\w*;)/ # html entity
|
424
|
+
print "add html ent: #{$1}\n"
|
425
|
+
@tree.add_raw($1)
|
412
426
|
when str =~ /\A([:alpha:]|[:digit:])+/
|
413
|
-
@
|
427
|
+
@tree.add($&) # word
|
414
428
|
when str =~ /\A\s+/
|
415
|
-
@
|
429
|
+
@tree.add_spc
|
416
430
|
when str =~ /\A'''''/
|
417
431
|
toggle_tag 'strongem', $& # bolditallic
|
418
432
|
when str =~ /\A\*\*/ || str =~ /\A'''/
|
@@ -420,25 +434,122 @@ module TracWiki
|
|
420
434
|
when str =~ /\A''/ || str =~ /\A\/\//
|
421
435
|
toggle_tag 'em', $& # italic
|
422
436
|
when str =~ /\A\\\\/ || str =~ /\A\[\[br\]\]/i
|
423
|
-
@
|
437
|
+
@tree.tag(:br) # newline
|
424
438
|
when str =~ /\A__/
|
425
439
|
toggle_tag 'u', $& # underline
|
426
440
|
when str =~ /\A~~/
|
427
441
|
toggle_tag 'del', $& # delete
|
442
|
+
when str =~ /\A~/
|
443
|
+
@tree.add_raw(' ') # tilde
|
428
444
|
# when /\A\+\+/
|
429
445
|
# toggle_tag 'ins', $& # insert
|
430
446
|
when str =~ /\A\^/
|
431
447
|
toggle_tag 'sup', $& # ^{}
|
432
448
|
when str =~ /\A,,/
|
433
449
|
toggle_tag 'sub', $& # _{}
|
434
|
-
when str =~ /\A!([^\s])/
|
435
|
-
@
|
450
|
+
when str =~ /\A!(\{\{|[^\s])/
|
451
|
+
@tree.add($1) # !neco !{{
|
436
452
|
when str =~ /./
|
437
|
-
@
|
453
|
+
@tree.add($&) # ordinal char
|
438
454
|
end
|
439
455
|
return $'
|
440
456
|
end
|
441
457
|
|
458
|
+
# r: expanded macro + rest of str, count lines taken from str
|
459
|
+
# sideefect: parse result of macro
|
460
|
+
def parse_macro(macro_name, str)
|
461
|
+
begin
|
462
|
+
mac_out, rest, lines = parse_macro_arg(macro_name, str, {})
|
463
|
+
#parse_inline(mac)
|
464
|
+
#@tree.add(mac)
|
465
|
+
#print "MACOUT:'#{mac_out}'\n"
|
466
|
+
return mac_out + rest, lines
|
467
|
+
rescue Exception => a
|
468
|
+
return "TOO_LONG_EXPANSION_OF_MACRO(#{macro_name})QUIT"
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
# read to args to }} (while balancing {{ and }})
|
473
|
+
# ret: (arg, rest, lines)
|
474
|
+
# mac_out -- string to }} (macros inside expanded)
|
475
|
+
# rest -- str aftrer }}
|
476
|
+
# lines -- howmany \n eaten from str (from begining to }})
|
477
|
+
def parse_macro_arg(macro_name, str, env)
|
478
|
+
|
479
|
+
lines = 0
|
480
|
+
arg = ''
|
481
|
+
# FIXME: MACRO_REX
|
482
|
+
# prefix }}... {{macro_name
|
483
|
+
while str =~ MACRO_END_REX
|
484
|
+
prefix, bracket, sub_macro_name, str = $1, $2, $3, $'
|
485
|
+
arg << prefix
|
486
|
+
lines += prefix.count("\n")
|
487
|
+
if bracket == '}}'
|
488
|
+
#print "prefix: #{prefix}\n"
|
489
|
+
env = do_macro_arg_to_env(arg, env[:depth])
|
490
|
+
return do_macro(macro_name, env), str, lines
|
491
|
+
end
|
492
|
+
|
493
|
+
# we need to go deeper!
|
494
|
+
mac_out, str, l = parse_macro_arg(sub_macro_name, str, env)
|
495
|
+
arg << mac_out
|
496
|
+
lines += l
|
497
|
+
end
|
498
|
+
raise "Error parsing macro near '#{str}' (arg:#{arg}, lines=#{lines})"
|
499
|
+
end
|
500
|
+
|
501
|
+
# expand macro `macro_name` with `args`
|
502
|
+
# afer expansion all {{macros}} will be expanded recursively
|
503
|
+
# r: expanded string
|
504
|
+
def do_macro(macro_name, env)
|
505
|
+
return "!{{toc}}" if macro_name == 'toc'
|
506
|
+
return env[:arg].strip if macro_name == '#echo'
|
507
|
+
return '' if macro_name == '#'
|
508
|
+
|
509
|
+
return do_macro_var(macro_name, env) if macro_name =~ /^\$/
|
510
|
+
|
511
|
+
|
512
|
+
if ! @template_handler.nil?
|
513
|
+
text = @template_handler.call(macro_name, env)
|
514
|
+
if !text.nil?
|
515
|
+
#print "dep:#{env[:depth]}(#{macro_name}, #{text})\n"
|
516
|
+
if env[:depth] > 32
|
517
|
+
return "TOO_DEEP_RECURSION(`#{text}`)\n"
|
518
|
+
#return "TOO_DEEP_RECURSION"
|
519
|
+
end
|
520
|
+
# FIXME: melo by nahlasit jestli to chce expandovat | wiki expadnovat |raw html
|
521
|
+
#print "temp(#{macro_name}) --> : #{text}\n"
|
522
|
+
text = do_macro_expand_result(text, env)
|
523
|
+
#print "af expand:#{text}\n"
|
524
|
+
|
525
|
+
return text
|
526
|
+
end
|
527
|
+
end
|
528
|
+
"UMACRO(#{macro_name}#{env[:arg]})"
|
529
|
+
end
|
530
|
+
|
531
|
+
def do_macro_var(macro_name, env)
|
532
|
+
"VAR(#{macro_name})"
|
533
|
+
end
|
534
|
+
|
535
|
+
def do_macro_arg_to_env(arg, depth)
|
536
|
+
{ arg: arg , depth: (depth||0) + 1 }
|
537
|
+
end
|
538
|
+
|
539
|
+
# template expand
|
540
|
+
def do_macro_expand_result(text, env)
|
541
|
+
ret = ''
|
542
|
+
while text =~ MACRO_BEG_INSIDE_REX
|
543
|
+
prefix, macro_name2, text = $1, $2, $'
|
544
|
+
ret << prefix
|
545
|
+
mac_out, text, lines = parse_macro_arg(macro_name2, text, env)
|
546
|
+
ret << mac_out
|
547
|
+
raise "Too long macro expadion" if ret.size > 1_000_000
|
548
|
+
end
|
549
|
+
return ret + text
|
550
|
+
end
|
551
|
+
|
552
|
+
|
442
553
|
def parse_table_row(str)
|
443
554
|
start_tag('tr') if !@stack.include?('tr')
|
444
555
|
colspan = 1
|
@@ -457,17 +568,17 @@ module TracWiki
|
|
457
568
|
next
|
458
569
|
end
|
459
570
|
|
460
|
-
style =
|
571
|
+
style = nil
|
461
572
|
if txt =~ /\S(\s*)$/
|
462
573
|
ri = $1.size
|
463
574
|
ri += 100 if tail.empty? # do not right when last || omnited
|
464
|
-
style =
|
465
|
-
style =
|
575
|
+
style = 'text-align:right' if ri == 0 && le >= 1
|
576
|
+
style = 'text-align:center' if le >= 2 && ri >= 2
|
466
577
|
#print "le#{le} ri#{ri} st:#{style}\n"
|
467
578
|
end
|
468
579
|
|
469
|
-
|
470
|
-
start_tag(tdth, style
|
580
|
+
colspan = colspan > 1 ? colspan : nil;
|
581
|
+
start_tag(tdth, { style:style, colspan: colspan});
|
471
582
|
colspan = 1
|
472
583
|
|
473
584
|
parse_inline(txt.strip) if txt
|
@@ -510,14 +621,15 @@ module TracWiki
|
|
510
621
|
if @stacki.empty? || @stacki.last < spc_size
|
511
622
|
bullet.gsub!(/\.$/,'')
|
512
623
|
ulol = bullet =~ /[-*]/ ? 'ul' : 'ol';
|
513
|
-
attr = ""
|
514
|
-
attr = " type='i'" if bullet =~ /i/i;
|
515
|
-
attr = " type='a'" if bullet =~ /a/i;
|
516
624
|
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
625
|
+
type = nil
|
626
|
+
type = 'i' if bullet =~ /i/i;
|
627
|
+
type = 'a' if bullet =~ /a/i;
|
628
|
+
|
629
|
+
start = nil
|
630
|
+
start = bullet if bullet =~ /^\d+$/ && bullet != '1'
|
631
|
+
|
632
|
+
start_tag(ulol, {type: type, start: start}, spc_size)
|
521
633
|
end
|
522
634
|
|
523
635
|
start_tag('li')
|
@@ -528,7 +640,7 @@ module TracWiki
|
|
528
640
|
def blockquote_level_to(level)
|
529
641
|
cur_level = @stack.count('blockquote')
|
530
642
|
if cur_level == level
|
531
|
-
@
|
643
|
+
@tree.add(' ')
|
532
644
|
return
|
533
645
|
end
|
534
646
|
while cur_level < level
|
@@ -541,100 +653,132 @@ module TracWiki
|
|
541
653
|
end
|
542
654
|
end
|
543
655
|
|
656
|
+
def do_math(text)
|
657
|
+
end_paragraph
|
658
|
+
@tree.add("$$#{text}$$\n")
|
659
|
+
@was_math = true
|
660
|
+
end
|
661
|
+
def do_merge(merge_type, who)
|
662
|
+
merge_class = case merge_type[0]
|
663
|
+
when '<' ; 'merge-mine'
|
664
|
+
when '=' ; 'merge-split'
|
665
|
+
when '|' ; 'merge-orig'
|
666
|
+
when '>' ; 'merge-your'
|
667
|
+
end
|
668
|
+
end_paragraph
|
669
|
+
@tree.tag(:div, { class: "merge #{merge_class}" }, who)
|
670
|
+
end
|
671
|
+
def do_pre(text)
|
672
|
+
end_paragraph
|
673
|
+
nowikiblock = make_nowikiblock(text)
|
674
|
+
@tree.tag(:pre, nowikiblock)
|
675
|
+
end
|
676
|
+
|
677
|
+
def do_raw_html(text)
|
678
|
+
end_paragraph
|
679
|
+
@tree.add_raw(text)
|
680
|
+
end
|
681
|
+
|
682
|
+
def do_hr
|
683
|
+
end_paragraph
|
684
|
+
@tree.tag(:hr)
|
685
|
+
end
|
686
|
+
|
687
|
+
def do_heading(level, title, aname)
|
688
|
+
aname= aname_nice(aname, title)
|
689
|
+
@headings.last[:eline] = @line_no - 1
|
690
|
+
@headings.push({ :title => title, :sline => @line_no, :aname => aname, :level => level, })
|
691
|
+
end_paragraph
|
692
|
+
make_headline(level, title, aname)
|
693
|
+
end
|
694
|
+
def do_table_row(text)
|
695
|
+
if !@stack.include?('table')
|
696
|
+
end_paragraph
|
697
|
+
start_tag('table')
|
698
|
+
end
|
699
|
+
parse_table_row(text)
|
700
|
+
end
|
701
|
+
def do_term(term)
|
702
|
+
start_tag('dl')
|
703
|
+
start_tag('dt')
|
704
|
+
@tree.add(term)
|
705
|
+
end_tag
|
706
|
+
start_tag('dd')
|
707
|
+
end
|
708
|
+
|
709
|
+
def do_citation(level, quote)
|
710
|
+
start_paragraph if !@stack.include? 'p'
|
711
|
+
blockquote_level_to(level)
|
712
|
+
parse_inline(quote.strip)
|
713
|
+
end
|
714
|
+
|
715
|
+
def do_ord_line(spc_size, text)
|
716
|
+
text.rstrip!
|
717
|
+
|
718
|
+
if @stack.include?('li') || @stack.include?('dl')
|
719
|
+
|
720
|
+
# dl, li continuation
|
721
|
+
parse_inline(' ')
|
722
|
+
parse_inline(text)
|
723
|
+
|
724
|
+
elsif spc_size > 0
|
725
|
+
# quote continuation
|
726
|
+
start_paragraph if !@stack.include? 'p'
|
727
|
+
blockquote_level_to(1)
|
728
|
+
parse_inline(text)
|
729
|
+
|
730
|
+
else
|
731
|
+
# real ordinary line
|
732
|
+
start_paragraph
|
733
|
+
parse_inline(text)
|
734
|
+
end
|
735
|
+
end
|
736
|
+
|
544
737
|
def parse_block(str)
|
738
|
+
#print "BLOCK.str(#{str})\n"
|
545
739
|
until str.empty?
|
546
740
|
case
|
547
|
-
#
|
741
|
+
# macro
|
742
|
+
when str =~ MACRO_BEG_REX
|
743
|
+
str, lines = parse_macro($1, $')
|
744
|
+
#print "MACRO.block(#{$1})\n"
|
745
|
+
next
|
746
|
+
# display math $$
|
548
747
|
when math? && str =~ /\A\$\$(.*?)\$\$/m
|
549
|
-
|
550
|
-
|
551
|
-
@out << "$$" << escape_html(nowikiblock) << "$$\n"
|
552
|
-
@was_math = true
|
748
|
+
do_math($1)
|
749
|
+
# merge
|
553
750
|
when merge? && str =~ /\A(<{7}|={7}|>{7}|\|{7}) *(\S*).*$(\r?\n)?/
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
when '>' ; 'merge-your'
|
560
|
-
end
|
561
|
-
end_paragraph
|
562
|
-
@out << "<div class='merge #{merge_class}'>" << escape_html(who) << "</div>\n"
|
751
|
+
do_merge($1, $2)
|
752
|
+
# raw_html {{{! ... }}}
|
753
|
+
when raw_html? && str =~ /\A\{\{\{!\r?\n(.*?)\r?\n\}\}\}/m
|
754
|
+
do_raw_html($1)
|
755
|
+
# pre {{{ ... }}}
|
563
756
|
when str =~ /\A\{\{\{\r?\n(.*?)\r?\n\}\}\}/m
|
564
|
-
|
565
|
-
nowikiblock = make_nowikiblock($1)
|
566
|
-
@out << '<pre>' << escape_html(nowikiblock) << '</pre>'
|
567
|
-
|
757
|
+
do_pre($1)
|
568
758
|
# horizontal rule
|
569
759
|
when str =~ /\A\s*-{4,}\s*$/
|
570
|
-
|
571
|
-
@out << '<hr/>'
|
572
|
-
|
760
|
+
do_hr()
|
573
761
|
# heading == Wiki Ruless ==
|
574
762
|
# heading == Wiki Ruless == #tag
|
575
763
|
when str =~ /\A[[:blank:]]*(={1,6})\s*(.*?)\s*=*\s*(#(\S*))?\s*$(\r?\n)?/
|
576
|
-
|
577
|
-
|
578
|
-
aname= aname_nice($4, title)
|
579
|
-
@headings.last[:eline] = @line_no - 1
|
580
|
-
@headings.push({ :title => title, :sline => @line_no, :aname => aname, :level => level, })
|
581
|
-
end_paragraph
|
582
|
-
@out << make_headline(level, title, aname)
|
583
|
-
|
584
|
-
# table row
|
764
|
+
do_heading($1.size, $2, $4)
|
765
|
+
# table row ||
|
585
766
|
when str =~ /\A[ \t]*\|\|(.*)$(\r?\n)?/
|
586
|
-
|
587
|
-
end_paragraph
|
588
|
-
start_tag('table')
|
589
|
-
end
|
590
|
-
parse_table_row($1)
|
591
|
-
|
767
|
+
do_table_row($1)
|
592
768
|
# empty line
|
593
769
|
when str =~ /\A\s*$(\r?\n)?/
|
594
770
|
end_paragraph
|
595
771
|
when str =~ /\A([:\w\s]+)::(\s+|\r?\n)/
|
596
|
-
|
597
|
-
start_tag('dl')
|
598
|
-
start_tag('dt')
|
599
|
-
@out << escape_html(term)
|
600
|
-
end_tag
|
601
|
-
start_tag('dd')
|
602
|
-
|
772
|
+
do_term($1)
|
603
773
|
# li
|
604
774
|
when str =~ /\A(\s*)([*-]|[aAIi\d]\.)\s+(.*?)$(\r?\n)?/
|
605
775
|
parse_li_line($1.size, $2, $3)
|
606
|
-
|
776
|
+
# citation
|
607
777
|
when str =~ /\A(>[>\s]*)(.*?)$(\r?\n)?/
|
608
|
-
|
609
|
-
level, quote = $1.count('>'), $2
|
610
|
-
|
611
|
-
start_paragraph if !@stack.include? 'p'
|
612
|
-
blockquote_level_to(level)
|
613
|
-
parse_inline(quote.strip)
|
614
|
-
|
615
|
-
|
778
|
+
do_citation($1.count('>'), $2)
|
616
779
|
# ordinary line
|
617
780
|
when str =~ /\A(\s*)(\S+.*?)$(\r?\n)?/
|
618
|
-
|
619
|
-
text.rstrip!
|
620
|
-
|
621
|
-
if @stack.include?('li') ||@stack.include?('dl')
|
622
|
-
|
623
|
-
# dl, li continuation
|
624
|
-
parse_inline(' ')
|
625
|
-
parse_inline(text)
|
626
|
-
|
627
|
-
elsif spc_size > 0
|
628
|
-
# quote continuation
|
629
|
-
start_paragraph if !@stack.include? 'p'
|
630
|
-
blockquote_level_to(1)
|
631
|
-
parse_inline(text)
|
632
|
-
|
633
|
-
else
|
634
|
-
# real ordinary line
|
635
|
-
start_paragraph
|
636
|
-
parse_inline(text)
|
637
|
-
end
|
781
|
+
do_ord_line($1.size, $2)
|
638
782
|
else # case str
|
639
783
|
raise "Parse error at #{str[0,30].inspect}"
|
640
784
|
end
|
@@ -643,7 +787,6 @@ module TracWiki
|
|
643
787
|
end
|
644
788
|
end_paragraph
|
645
789
|
@headings.last[:eline] = @line_no - 1
|
646
|
-
@out
|
647
790
|
end
|
648
791
|
|
649
792
|
def aname_nice(aname, title)
|
@@ -664,8 +807,5 @@ module TracWiki
|
|
664
807
|
@anames[aname] = true
|
665
808
|
aname
|
666
809
|
end
|
667
|
-
|
668
|
-
|
669
|
-
|
670
810
|
end
|
671
811
|
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'sanitize'
|
3
|
+
module TracWiki
|
4
|
+
|
5
|
+
class RawHtml
|
6
|
+
def initialize(text)
|
7
|
+
@text = text
|
8
|
+
end
|
9
|
+
def to_s
|
10
|
+
@text
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Node
|
15
|
+
attr_accessor :tag
|
16
|
+
attr_accessor :par
|
17
|
+
attr_accessor :cont
|
18
|
+
attr_accessor :attrs
|
19
|
+
def initialize(tag_name, par=nil, attrs={}, cont=[])
|
20
|
+
@tag = nil
|
21
|
+
@tag = tag_name.to_sym if tag_name
|
22
|
+
@par = par
|
23
|
+
cont = [ cont ] if cont.is_a? String
|
24
|
+
@cont = cont || []
|
25
|
+
@attrs = attrs || {}
|
26
|
+
end
|
27
|
+
|
28
|
+
def add(cont)
|
29
|
+
@cont << cont
|
30
|
+
end
|
31
|
+
end
|
32
|
+
class Tree
|
33
|
+
|
34
|
+
def initialize
|
35
|
+
@root = Node.new(nil)
|
36
|
+
@cur = @root
|
37
|
+
end
|
38
|
+
|
39
|
+
def tag(tag, attrs = nil, cont = nil)
|
40
|
+
if cont.nil? && ! attrs.is_a?(Hash)
|
41
|
+
# tag(:b, "ahoj") -> tag(:b, {}, "ahoj")
|
42
|
+
cont = attrs
|
43
|
+
attrs = nil
|
44
|
+
end
|
45
|
+
cont = [ cont ] if cont.is_a? String
|
46
|
+
@cur.add(Node.new(tag, @cur, attrs, cont))
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def tag_beg(tag_name, attrs = nil, cont = nil)
|
51
|
+
node = Node.new(tag_name, @cur, attrs, cont)
|
52
|
+
@cur.add(node)
|
53
|
+
@cur = node
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
def tag_end(tag_name)
|
58
|
+
if @cur.tag == tag_name.to_sym
|
59
|
+
@cur = @cur.par
|
60
|
+
else
|
61
|
+
raise "tag_end: cur tag is not <#{tag_name}>, but <#{@cur.tag}>"
|
62
|
+
end
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
# add space if needed
|
67
|
+
def add_spc
|
68
|
+
if @cur.cont.size > 0
|
69
|
+
last = @cur.cont.last
|
70
|
+
if last.is_a?(String) && last[-1] == ?\s
|
71
|
+
return
|
72
|
+
end
|
73
|
+
end
|
74
|
+
add(' ')
|
75
|
+
end
|
76
|
+
|
77
|
+
def add(cont)
|
78
|
+
@cur.add(cont)
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
def add_raw(cont)
|
83
|
+
cont_san = Sanitize.clean(cont, san_conf)
|
84
|
+
@cur.add(RawHtml.new(cont_san))
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def find_par(tag_name, node = nil)
|
90
|
+
node = @cur if node.nil?
|
91
|
+
while ! node.par.nil?
|
92
|
+
if node.tag == tag_name
|
93
|
+
return node.par
|
94
|
+
end
|
95
|
+
node = node.par
|
96
|
+
end
|
97
|
+
nil
|
98
|
+
end
|
99
|
+
|
100
|
+
def to_html
|
101
|
+
tree_to_html(@root)
|
102
|
+
end
|
103
|
+
|
104
|
+
def tree_to_html(node)
|
105
|
+
tag = node.tag
|
106
|
+
if tag.nil?
|
107
|
+
return cont_to_s(node.cont)
|
108
|
+
end
|
109
|
+
|
110
|
+
nl = ""
|
111
|
+
#nl = "\n" if [:div, :h1, :h2, :h3, :h4, :h5, :p].include? tag
|
112
|
+
nl = "\n" if [:div, :p].include? tag
|
113
|
+
|
114
|
+
if node.cont.size == 0
|
115
|
+
if [:a, :td, :h1, :h2, :h3, :h4, :h5, :h6,:strong, :script].include? tag
|
116
|
+
return "<#{tag}#{attrs_to_s(node.attrs)}></#{tag}>"
|
117
|
+
end
|
118
|
+
return "<#{tag}#{attrs_to_s(node.attrs)}/>#{nl}"
|
119
|
+
end
|
120
|
+
|
121
|
+
return "<#{tag}#{attrs_to_s(node.attrs)}>#{cont_to_s(node.cont)}</#{tag}>#{nl}"
|
122
|
+
end
|
123
|
+
|
124
|
+
def cont_to_s(cont)
|
125
|
+
cont = [cont] if cont.is_a? String
|
126
|
+
cont.map do |c|
|
127
|
+
if c.is_a? Node
|
128
|
+
tree_to_html(c)
|
129
|
+
elsif c.is_a? RawHtml
|
130
|
+
c.to_s
|
131
|
+
else
|
132
|
+
TracWiki::Parser.escapeHTML(c.to_s)
|
133
|
+
end
|
134
|
+
end.join('')
|
135
|
+
end
|
136
|
+
|
137
|
+
def attrs_to_s(attrs)
|
138
|
+
return '' if attrs.nil? || attrs.size == 0
|
139
|
+
ret = ['']
|
140
|
+
attrs.each_pair do |k,v|
|
141
|
+
ret.push "#{TracWiki::Parser.escapeHTML(k.to_s)}=\"#{TracWiki::Parser.escapeHTML(v.to_s)}\"" if !v.nil?
|
142
|
+
end
|
143
|
+
return ret.sort.join(' ')
|
144
|
+
end
|
145
|
+
|
146
|
+
def san_conf
|
147
|
+
return @san_conf if @san_conf
|
148
|
+
conf = { elements: ['form', 'input'],
|
149
|
+
attributes: { 'form' => ['action', 'meth'],
|
150
|
+
'input' => ['type', 'value'],
|
151
|
+
},
|
152
|
+
}
|
153
|
+
|
154
|
+
@san_conf = conf.merge(Sanitize::Config::RELAXED){|k,o,n| o.is_a?(Hash) ? o.merge(n) :
|
155
|
+
o.is_a?(Array) ? o + n :
|
156
|
+
n }
|
157
|
+
|
158
|
+
#pp @san_conf
|
159
|
+
@san_conf
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
data/lib/trac-wiki/version.rb
CHANGED
data/test/parser_test.rb
CHANGED
@@ -1,11 +1,30 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
require 'trac-wiki'
|
2
3
|
require 'pp'
|
3
4
|
|
4
5
|
|
5
6
|
class Bacon::Context
|
6
7
|
def tc(html, wiki, options = {})
|
8
|
+
#options[:template_handler] = proc {|tname,env| template_handler(tname, env) }
|
9
|
+
options[:template_handler] = self.method(:template_handler)
|
7
10
|
TracWiki.render(wiki, options).should.equal html
|
8
11
|
end
|
12
|
+
|
13
|
+
def template_handler(tname, env)
|
14
|
+
case tname
|
15
|
+
when 'test'
|
16
|
+
"{{west}}"
|
17
|
+
when 'west'
|
18
|
+
"WEST"
|
19
|
+
when 'deep'
|
20
|
+
"{{deep}}"
|
21
|
+
when 'wide'
|
22
|
+
"0123456789{{wide}}" * 10
|
23
|
+
else
|
24
|
+
nil
|
25
|
+
#"UNK_TEMPL(#{tname})"
|
26
|
+
end
|
27
|
+
end
|
9
28
|
def h(hash, wiki, opts = {})
|
10
29
|
parser = TracWiki.parser(wiki, opts)
|
11
30
|
parser.to_html
|
@@ -58,7 +77,8 @@ describe TracWiki::Parser do
|
|
58
77
|
it 'should be toc' do
|
59
78
|
tc "<p>{{toc}}</p>\n", "{{toc}}"
|
60
79
|
tc "<h2>ahoj</h2><p>{{toc}}</p>\n<h2>ahoj</h2>", "==ahoj==\n{{toc}}\n\n==ahoj==\n"
|
61
|
-
tc "
|
80
|
+
#tc "{{toc}}", "{{toc}}"
|
81
|
+
#tc "<h2>ahoj</h2>{{toc}}<h2>ahoj</h2>", "==ahoj==\r\n{{toc}}\r\n\r\n==ahoj==\r\n"
|
62
82
|
end
|
63
83
|
|
64
84
|
it 'should parse bolditalic' do
|
@@ -70,6 +90,7 @@ describe TracWiki::Parser do
|
|
70
90
|
end
|
71
91
|
it 'should parse monospace' do
|
72
92
|
tc "<p>This is <tt>monospace</tt>.</p>\n", "This is {{{monospace}}}."
|
93
|
+
tc "<p>This is not {{{monospace}}}.</p>\n", "This is not !{{{monospace}}}."
|
73
94
|
tc "<p>This is <tt>mon**o**space</tt>.</p>\n", "This is {{{mon**o**space}}}."
|
74
95
|
tc "<p>This is <tt>mon<o>space</tt>.</p>\n", "This is {{{mon<o>space}}}."
|
75
96
|
tc "<p>This is <tt>mon''o''space</tt>.</p>\n", "This is {{{mon''o''space}}}."
|
@@ -149,6 +170,7 @@ describe TracWiki::Parser do
|
|
149
170
|
tc "<h1>Heading 1</h1>", "= Heading 1 ="
|
150
171
|
tc "<h2>Heading 2</h2>", "== Heading 2 =="
|
151
172
|
tc "<h3>Heading 3</h3>", "=== Heading 3 ==="
|
173
|
+
tc "<h3>Heading 3\u00a0B</h3>", "=== Heading 3~B ==="
|
152
174
|
tc "<h3 id=\"HE3\">Heading 3</h3>", "=== Heading 3 === #HE3"
|
153
175
|
tc "<h3 id=\"Heading-3\">Heading 3</h3>", "=== Heading 3 === #Heading-3"
|
154
176
|
tc "<h3 id=\"Heading/3\">Heading 3</h3>", "=== Heading 3 === #Heading/3"
|
@@ -192,6 +214,8 @@ describe TracWiki::Parser do
|
|
192
214
|
it 'should parse links' do
|
193
215
|
# Links
|
194
216
|
tc "<p><a href=\"link\">link</a></p>\n", "[[link]]"
|
217
|
+
tc "<p><a href=\"BASE/link\">link</a></p>\n", "[[link]]", base: 'BASE'
|
218
|
+
tc "<p><a href=\"BASE/link\">link</a></p>\n", "[[link]]", base: 'BASE/'
|
195
219
|
tc "<p><a href=\"link#link\">link#link</a></p>\n", "[[link#link]]"
|
196
220
|
tc "<p><a href=\"#link\">#link</a></p>\n", "[[#link]]"
|
197
221
|
|
@@ -217,7 +241,7 @@ describe TracWiki::Parser do
|
|
217
241
|
|
218
242
|
# WRNING: Parsing markup within a link is optional
|
219
243
|
tc "<p><a href=\"Weird+Stuff\"><strong>Weird</strong> <em>Stuff</em></a></p>\n", "[[Weird Stuff|**Weird** ''Stuff'']]"
|
220
|
-
#tc("<p><a href=\"http://example.org/\"><img src
|
244
|
+
#tc("<p><a href=\"http://example.org/\"><img src=\"image.jpg\"/></a></p>\n", "[[http://example.org/|{{image.jpg}}]]")
|
221
245
|
|
222
246
|
# Inside bold
|
223
247
|
tc "<p><strong><a href=\"link\">link</a></strong></p>\n", "**[[link]]**"
|
@@ -252,6 +276,7 @@ describe TracWiki::Parser do
|
|
252
276
|
it 'should parse paragraphs' do
|
253
277
|
# One or more blank lines end paragraphs.
|
254
278
|
tc "<p>This is my text.</p>\n<p>This is more text.</p>\n", "This is\nmy text.\n\nThis is\nmore text."
|
279
|
+
tc "<p>This is my text.</p>\n<p>This is more text.</p>\n", "This is \nmy text.\n\nThis is\nmore text."
|
255
280
|
tc "<p>This is my text.</p>\n<p>This is more text.</p>\n", "This is\nmy text.\n\n\nThis is\nmore text."
|
256
281
|
tc "<p>This is my text.</p>\n<p>This is more text.</p>\n", "This is\nmy text.\n\n\n\nThis is\nmore text."
|
257
282
|
|
@@ -459,6 +484,7 @@ describe TracWiki::Parser do
|
|
459
484
|
it 'should parse ambiguious bold and lists' do
|
460
485
|
tc "<p><strong> bold text </strong></p>\n", "** bold text **"
|
461
486
|
tc "<p><blockquote><strong> bold text </strong></blockquote></p>\n", " ** bold text **"
|
487
|
+
tc "<p><blockquote><strong> bold text </strong></blockquote></p>\n", " ** bold\ntext **"
|
462
488
|
end
|
463
489
|
|
464
490
|
it 'should parse nowiki' do
|
@@ -498,8 +524,8 @@ describe TracWiki::Parser do
|
|
498
524
|
# Image tags should be escape
|
499
525
|
tc("<p><img src=\"image.jpg\"/></p>\n", "[[Image(image.jpg)]]")
|
500
526
|
tc("<p><img src=\"image.jpg\"/></p>\n", "[[Image(image.jpg)]]", :no_link=>true)
|
501
|
-
tc("<p><img
|
502
|
-
tc("<p><img
|
527
|
+
tc("<p><img alt=\"a%22tag%22\" src=\"image.jpg\"/></p>\n", "[[Image(image.jpg,alt=a\"tag\")]]")
|
528
|
+
tc("<p><img alt=\"a%22tag%22\" src=\"image.jpg\"/></p>\n", "[[Image(image.jpg,alt=a\"tag\")]]", :no_link=>true)
|
503
529
|
|
504
530
|
# Malicious links should not be converted.
|
505
531
|
tc("<p><a href=\"javascript%3Aalert%28%22Boo%21%22%29\">Click</a></p>\n", "[[javascript:alert(\"Boo!\")|Click]]")
|
@@ -510,7 +536,7 @@ describe TracWiki::Parser do
|
|
510
536
|
tc "<p>// Not Italic //</p>\n", "!// Not Italic !//"
|
511
537
|
tc "<p>* Not Bullet</p>\n", "!* Not Bullet"
|
512
538
|
# Following char is not a blank (space or line feed)
|
513
|
-
tc "<p>Hello
|
539
|
+
tc "<p>Hello \u00a0 world</p>\n", "Hello ~ world\n"
|
514
540
|
tc "<p>Hello ! world</p>\n", "Hello ! world\n"
|
515
541
|
tc "<p>Hello ! world</p>\n", "Hello ! world\n"
|
516
542
|
tc "<p>Hello ! world</p>\n", "Hello !\nworld\n"
|
@@ -550,19 +576,19 @@ describe TracWiki::Parser do
|
|
550
576
|
tc "<table><tr><td>Hello</td><td>World!</td></tr></table>", "||Hello||World!||"
|
551
577
|
tc "<table><tr><td>Hello</td><td>World!</td></tr></table>", "||Hello||\\\n||World!||"
|
552
578
|
tc "<table><tr><td>He</td><td>llo</td><td>World!</td></tr></table>", "||He||llo||\\\n||World!||"
|
553
|
-
tc "<table><tr><td>Hello</td><td colspan
|
554
|
-
tc "<table><tr><td>Hello</td><td colspan
|
555
|
-
tc "<table><tr><td>1</td><td>2</td><td>3</td></tr><tr><td colspan
|
579
|
+
tc "<table><tr><td>Hello</td><td colspan=\"2\">World!</td></tr></table>", "||Hello||||World!||"
|
580
|
+
tc "<table><tr><td>Hello</td><td colspan=\"2\">kuk</td><td>World!</td></tr></table>", "||Hello||||kuk||\\\n||World!||"
|
581
|
+
tc "<table><tr><td>1</td><td>2</td><td>3</td></tr><tr><td colspan=\"2\">1-2</td><td>3</td></tr><tr><td>1</td><td colspan=\"2\">2-3</td></tr><tr><td colspan=\"3\">1-2-3</td></tr></table>", "|| 1 || 2 || 3 ||\n|||| 1-2 || 3 ||\n|| 1 |||| 2-3 ||\n|||||| 1-2-3 ||\n"
|
556
582
|
|
557
|
-
tc "<table><tr><td>table</td><td style
|
558
|
-
tc "<table><tr><td>table</td><td style
|
559
|
-
tc "<table><tr><td>table</td><td style
|
583
|
+
tc "<table><tr><td>table</td><td style=\"text-align:center\">center</td></tr></table>", "||table|| center ||"
|
584
|
+
tc "<table><tr><td>table</td><td style=\"text-align:right\">right</td></tr></table>", "||table|| right||"
|
585
|
+
tc "<table><tr><td>table</td><td style=\"text-align:center\">center</td><td style=\"text-align:right\">right</td></tr></table>", "||table|| center || right||"
|
560
586
|
|
561
587
|
tc "<table><tr><td>Hello, World!</td></tr></table>", "||Hello, World!||"
|
562
|
-
tc "<table><tr><td style
|
563
|
-
tc "<table><tr><th style
|
564
|
-
tc "<table><tr><td style
|
565
|
-
tc "<table><tr><th style
|
588
|
+
tc "<table><tr><td style=\"text-align:right\">Hello, Right World!</td></tr></table>", "|| Hello, Right World!||"
|
589
|
+
tc "<table><tr><th style=\"text-align:right\">Hello, Right World!</th></tr></table>", "||= Hello, Right World!=||"
|
590
|
+
tc "<table><tr><td style=\"text-align:center\">Hello, Centered World!</td></tr></table>", "|| Hello, Centered World! ||"
|
591
|
+
tc "<table><tr><th style=\"text-align:center\">Hello, Centered World!</th></tr></table>", "||= Hello, Centered World! =||"
|
566
592
|
# Multiple columns
|
567
593
|
tc "<table><tr><td>c1</td><td>c2</td><td>c3</td></tr></table>", "||c1||c2||c3||"
|
568
594
|
# Multiple rows
|
@@ -757,16 +783,16 @@ describe TracWiki::Parser do
|
|
757
783
|
|
758
784
|
it 'should parse image' do
|
759
785
|
tc("<p><img src=\"image.jpg\"/></p>\n", "[[Image(image.jpg)]]")
|
760
|
-
tc("<p><img src=\"javascript%3Aimage.jpg\"
|
761
|
-
tc("<p><img
|
786
|
+
tc("<p><img alt=\"tag\" src=\"javascript%3Aimage.jpg\"/></p>\n", "[[Image(javascript:image.jpg,alt=tag)]]")
|
787
|
+
tc("<p><img alt=\"tag\" src=\"image.jpg\"/></p>\n", "[[Image(image.jpg,alt=tag)]]")
|
762
788
|
tc("<p><img src=\"image.jpg\" width=\"120px\"/></p>\n", "[[Image(image.jpg, 120px )]]")
|
763
789
|
tc("<p><img src=\"image.jpg\" width=\"120px\"/></p>\n", "[[Image(image.jpg, \t120px )]]")
|
764
|
-
tc("<p><img
|
765
|
-
tc("<p><img
|
766
|
-
tc("<p><img
|
790
|
+
tc("<p><img align=\"right\" src=\"image.jpg\"/></p>\n", "[[Image(image.jpg, right)]]")
|
791
|
+
tc("<p><img align=\"right\" src=\"image.jpg\" valign=\"top\"/></p>\n", "[[Image(image.jpg, right,top)]]")
|
792
|
+
tc("<p><img align=\"right\" src=\"image.jpg\" valign=\"top\"/></p>\n", "[[Image(image.jpg, top,right)]]")
|
767
793
|
tc("<p><img src=\"image.jpg\" valign=\"top\"/></p>\n", "[[Image(image.jpg, top)]]")
|
768
794
|
tc("<p><img src=\"image.jpg\" valign=\"top\"/></p>\n", "[[Image(image.jpg, valign=top)]]")
|
769
|
-
tc("<p><img
|
795
|
+
tc("<p><img align=\"center\" src=\"image.jpg\"/></p>\n", "[[Image(image.jpg, center)]]")
|
770
796
|
tc("<p><img src=\"image.jpg\" valign=\"middle\"/></p>\n", "[[Image(image.jpg, middle)]]")
|
771
797
|
tc("<p><img src=\"image.jpg\" title=\"houhouhou\"/></p>\n", "[[Image(image.jpg, title=houhouhou)]]")
|
772
798
|
tc("<p><img src=\"image.jpg\" width=\"120px\"/></p>\n", "[[Image(image.jpg,width=120px)]]")
|
@@ -807,12 +833,12 @@ describe TracWiki::Parser do
|
|
807
833
|
tc("<p><a href=\"a/b/c\">a/b/c</a></p>\n", "[[a/b/c]]", :no_escape => true)
|
808
834
|
end
|
809
835
|
it 'should support merge' do
|
810
|
-
tc "<div class
|
811
|
-
tc "<div class
|
812
|
-
tc "<div class
|
813
|
-
tc "<p>bhoj</p>\n<div class
|
814
|
-
tc "<div class
|
815
|
-
tc "<div class
|
836
|
+
tc "<div class=\"merge merge-orig\">orig</div>\n", "||||||| orig", :merge => true
|
837
|
+
tc "<div class=\"merge merge-mine\">mine</div>\n", "<<<<<<< mine", :merge => true
|
838
|
+
tc "<div class=\"merge merge-your\">your</div>\n", ">>>>>>> your", :merge => true
|
839
|
+
tc "<p>bhoj</p>\n<div class=\"merge merge-your\">your</div>\n<p>ahoj</p>\n", "bhoj\n>>>>>>> your\nahoj", :merge => true
|
840
|
+
tc "<div class=\"merge merge-split\"></div>\n<p>ahoj</p>\n", "=======\nahoj\n", :merge => true
|
841
|
+
tc "<div class=\"merge merge-split\">split</div>\n", "======= split", :merge => true
|
816
842
|
|
817
843
|
tc "<h6></h6><p>ahoj</p>\n", "=======\nahoj\n", :merge => false
|
818
844
|
end
|
@@ -853,6 +879,52 @@ kuk
|
|
853
879
|
|
854
880
|
eos
|
855
881
|
|
882
|
+
|
883
|
+
it 'should support macro' do
|
884
|
+
tc "<p>ahoj</p>\n" , "{{#echo \nahoj\n}}"
|
885
|
+
tc "<h2>H2</h2>" , "{{#echo == H2 ==}}"
|
886
|
+
tc "<h2>H2</h2>" , "{{#echo =={{#echo H2}}==}}"
|
887
|
+
tc "<h3 id=\"test\">H3</h3>" , "{{#echo =={{#echo =H3=}}=={{#echo #test}}}}"
|
888
|
+
|
889
|
+
tc "<p>This is correct</p>\n" , "This is {{# NOT}} correct"
|
890
|
+
tc "<h1>h1</h1>" , "{{# comment }}\n= h1 =\n"
|
891
|
+
tc "<h1>h1</h1>" , "{{# comment }}\n\n\n= h1 =\n"
|
892
|
+
tc "<h1>h1</h1>" , "{{# comment }}\n\n\n= h1 =\n{{# Comment2}}\n"
|
893
|
+
|
894
|
+
tc "<h1>h1</h1>" , "{{# co{{HUU}}mment }}\n\n\n= h1 =\n{{# Comment2}}\n"
|
895
|
+
|
896
|
+
tc "<p>UMACRO(macr ahoj )</p>\n" , "{{macr\nahoj\n}}"
|
897
|
+
tc "<p>ahoj UMACRO(macrUMACRO(o))</p>\n" , "ahoj {{macr{{o}}}}"
|
898
|
+
tc "<p>ahoj UMACRO(macro)</p>\n" , "ahoj {{macro}}"
|
899
|
+
tc "<p>ahoj {{%macrUMACRO(o)}}</p>\n" , "ahoj {{%macr{{o}}}}"
|
900
|
+
tc "<p>ahoj UMACRO(macrUMACRO(mac <strong>o</strong>))</p>\n" , "ahoj {{macr{{mac **o**}}}}"
|
901
|
+
tc "<p>ahoj VAR($mac)</p>\n" , "ahoj {{$mac|ahoj}}"
|
902
|
+
end
|
903
|
+
|
904
|
+
it 'should do temlate' do
|
905
|
+
tc "<p>1WEST</p>\n", "1{{west}}"
|
906
|
+
tc "<p>2WEST</p>\n", "2{{test}}"
|
907
|
+
|
908
|
+
# macro errors:
|
909
|
+
tc "<p>TOO_DEEP_RECURSION(<tt>{{deep}}</tt>) 3</p>\n", "{{deep}}3"
|
910
|
+
tc "<p>TOO_LONG_EXPANSION_OF_MACRO(wide)QUIT</p>\n", "{{wide}}3"
|
911
|
+
tc "<p>UMACRO(unknown)3</p>\n", "{{unknown}}3"
|
912
|
+
end
|
913
|
+
it 'should support options' do
|
914
|
+
tc "<h3>h1<a class=\"editheading\" href=\"?edit=1\">edit</a></h3>", "=== h1 ==", edit_heading: true
|
915
|
+
end
|
916
|
+
it 'should not html' do
|
917
|
+
tc "<p>{{{! <a></a> }}}</p>\n", "{{{!\n<a></a>\n}}}\n"
|
918
|
+
tc '<a></a>', "{{{!\n<a></a>\n}}}\n", raw_html: true
|
919
|
+
tc '<a></a>', "{{{!\n<a></a>\n}}}\n", raw_html: true
|
920
|
+
tc "<form meth=\"POST\" action=\"http://www.example.com\"><input type=\"hidden\" value=\"VAL\"></form>",
|
921
|
+
"{{{!\n<form meth=\"POST\" action=\"http://www.example.com\"><input type=\"hidden\" value=\"VAL\"/></form>\n}}}\n", raw_html: true
|
922
|
+
tc 'alert(444);', "{{{!\n<script>alert(444);</script>\n}}}\n", raw_html: true
|
923
|
+
end
|
924
|
+
it 'should not entity' do
|
925
|
+
tc "<p>\u00a0</p>\n", " "
|
926
|
+
tc "<p>„text“</p>\n", "„text“"
|
927
|
+
end
|
856
928
|
end
|
857
929
|
end
|
858
930
|
# vim: tw=0
|
data/test/tree_test.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'trac-wiki'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
class Bacon::Context
|
7
|
+
end
|
8
|
+
describe TracWiki::Parser do
|
9
|
+
it 'should work' do
|
10
|
+
t = TracWiki::Tree.new
|
11
|
+
t.tag_beg(:html)
|
12
|
+
t.tag_beg(:body, {hus:'JAN', mistr: nil})
|
13
|
+
t.tag(:div, {ahoj: "ahoj", bhoj: "BHOJ"})
|
14
|
+
t.tag(:br)
|
15
|
+
t.add("bye")
|
16
|
+
t.add_spc
|
17
|
+
t.add("bye ")
|
18
|
+
t.add_spc
|
19
|
+
t.add("bye")
|
20
|
+
t.tag_end(:body)
|
21
|
+
t.tag_end(:html)
|
22
|
+
t.add('\bye')
|
23
|
+
t.add_raw('>')
|
24
|
+
t.add_raw(' ')
|
25
|
+
t.add_raw('„')
|
26
|
+
|
27
|
+
res = "<html><body hus=\"JAN\"><div ahoj=\"ahoj\" bhoj=\"BHOJ\"/>\n<br/>bye bye bye</body></html>\\bye"
|
28
|
+
res += ">"
|
29
|
+
res += "\u00a0"
|
30
|
+
res += "„"
|
31
|
+
|
32
|
+
#print "\n#{t.to_html}\n#{res}"
|
33
|
+
t.to_html.should.equal res
|
34
|
+
end
|
35
|
+
end
|
metadata
CHANGED
@@ -1,41 +1,46 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trac-wiki
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.16
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Vitas Stradal
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2013-
|
12
|
+
date: 2013-12-27 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: bacon
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
16
18
|
requirements:
|
17
|
-
- - '>='
|
19
|
+
- - ! '>='
|
18
20
|
- !ruby/object:Gem::Version
|
19
21
|
version: '0'
|
20
22
|
type: :development
|
21
23
|
prerelease: false
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
23
26
|
requirements:
|
24
|
-
- - '>='
|
27
|
+
- - ! '>='
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: '0'
|
27
30
|
- !ruby/object:Gem::Dependency
|
28
31
|
name: rake
|
29
32
|
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
30
34
|
requirements:
|
31
|
-
- - '>='
|
35
|
+
- - ! '>='
|
32
36
|
- !ruby/object:Gem::Version
|
33
37
|
version: '0'
|
34
38
|
type: :development
|
35
39
|
prerelease: false
|
36
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
37
42
|
requirements:
|
38
|
-
- - '>='
|
43
|
+
- - ! '>='
|
39
44
|
- !ruby/object:Gem::Version
|
40
45
|
version: '0'
|
41
46
|
description: TracWiki markup language render (http://trac.edgewall.org/wiki/WikiFormatting
|
@@ -48,37 +53,42 @@ extensions: []
|
|
48
53
|
extra_rdoc_files:
|
49
54
|
- README
|
50
55
|
files:
|
56
|
+
- .gitignore
|
51
57
|
- Gemfile
|
58
|
+
- Gemfile.lock
|
52
59
|
- README
|
53
60
|
- Rakefile
|
54
61
|
- bin/trac-wiki.rb
|
55
62
|
- lib/trac-wiki.rb
|
56
63
|
- lib/trac-wiki/parser.rb
|
64
|
+
- lib/trac-wiki/tree.rb
|
57
65
|
- lib/trac-wiki/version.rb
|
58
66
|
- test/parser_test.rb
|
67
|
+
- test/tree_test.rb
|
59
68
|
- trac-wiki.gemspec
|
60
69
|
homepage: http://github.com/vitstradal/trac-wiki
|
61
70
|
licenses:
|
62
71
|
- GPL-2
|
63
|
-
metadata: {}
|
64
72
|
post_install_message:
|
65
73
|
rdoc_options: []
|
66
74
|
require_paths:
|
67
75
|
- lib
|
68
76
|
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
69
78
|
requirements:
|
70
|
-
- - '>='
|
79
|
+
- - ! '>='
|
71
80
|
- !ruby/object:Gem::Version
|
72
81
|
version: '0'
|
73
82
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
74
84
|
requirements:
|
75
|
-
- - '>='
|
85
|
+
- - ! '>='
|
76
86
|
- !ruby/object:Gem::Version
|
77
87
|
version: '0'
|
78
88
|
requirements: []
|
79
89
|
rubyforge_project: trac-wiki
|
80
|
-
rubygems_version:
|
90
|
+
rubygems_version: 1.8.23
|
81
91
|
signing_key:
|
82
|
-
specification_version:
|
92
|
+
specification_version: 3
|
83
93
|
summary: Trac Wiki markup language
|
84
94
|
test_files: []
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: 5c3c0e79552d6d60ecbb77c54fbaa434d208ca56
|
4
|
-
data.tar.gz: dd2e9ab2b74410c6b3abf6265d43185fcaec19cd
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: c173fe3e96fdceaa1e587c2a41e75e50fa731bfb3403270463d3352014e8223dd459ba7df0e5ea9d6377be54d701d19ec3a00dfb3b259583cd70325ab9d5bc15
|
7
|
-
data.tar.gz: b7c6a4d413d44ea1bb30d9e49454420a5ecd639601ea79ef19f80a73e1831c1165bac4d94b9da75757d5ca440fc301ff5a062554329293f8bb5821e41a296e0f
|