trac-wiki 0.1.12 → 0.2.16
Sign up to get free protection for your applications and to get access to all the features.
- 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
|