Soks 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/LICENSE.txt +60 -0
  2. data/README.txt +65 -0
  3. data/bin/soks-create-wiki.rb +41 -0
  4. data/contrib/diff/lcs.rb +1105 -0
  5. data/contrib/diff/lcs/array.rb +21 -0
  6. data/contrib/diff/lcs/block.rb +51 -0
  7. data/contrib/diff/lcs/callbacks.rb +322 -0
  8. data/contrib/diff/lcs/change.rb +169 -0
  9. data/contrib/diff/lcs/hunk.rb +257 -0
  10. data/contrib/diff/lcs/ldiff.rb +226 -0
  11. data/contrib/diff/lcs/string.rb +19 -0
  12. data/contrib/diff_licence.txt +76 -0
  13. data/contrib/redcloth-2.0.11.rb +894 -0
  14. data/contrib/redcloth-3.0.1.rb +1019 -0
  15. data/contrib/redcloth_license.txt +27 -0
  16. data/lib/authenticators.rb +79 -0
  17. data/lib/soks-helpers.rb +321 -0
  18. data/lib/soks-model.rb +208 -0
  19. data/lib/soks-servlet.rb +125 -0
  20. data/lib/soks-utils.rb +80 -0
  21. data/lib/soks-view.rb +424 -0
  22. data/lib/soks.rb +19 -0
  23. data/template/attachment/logo.png +0 -0
  24. data/template/attachment/stylesheet.css +63 -0
  25. data/template/content/How%20to%20export%20a%20site%20from%20this%20wiki.textile +5 -0
  26. data/template/content/How%20to%20hack%20soks.textile +60 -0
  27. data/template/content/How%20to%20import%20a%20site%20from%20instiki.textile +13 -0
  28. data/template/content/Improving%20the%20style%20of%20this%20wiki.textile +30 -0
  29. data/template/content/Picture%20of%20a%20pair%20of%20soks.textile +1 -0
  30. data/template/content/Pointers%20on%20adjusting%20the%20settings.textile +39 -0
  31. data/template/content/Pointers%20on%20how%20to%20use%20this%20wiki.textile +21 -0
  32. data/template/content/Recent%20Changes%20to%20This%20Site.textile +203 -0
  33. data/template/content/Soks%20Licence.textile +64 -0
  34. data/template/content/home%20page.textile +18 -0
  35. data/template/start.rb +74 -0
  36. data/template/views/AttachmentPage_edit.rhtml +36 -0
  37. data/template/views/ImagePage_edit.rhtml +36 -0
  38. data/template/views/Page_content.rhtml +1 -0
  39. data/template/views/Page_edit.rhtml +34 -0
  40. data/template/views/Page_print.rhtml +5 -0
  41. data/template/views/Page_revisions.rhtml +18 -0
  42. data/template/views/Page_rss.rhtml +34 -0
  43. data/template/views/Page_search_results.rhtml +19 -0
  44. data/template/views/Page_view.rhtml +3 -0
  45. data/template/views/frame.rhtml +34 -0
  46. metadata +88 -0
@@ -0,0 +1,1019 @@
1
+ # vim:ts=4:sw=4:
2
+ # = RedCloth - Textile and Markdown Hybrid for Ruby
3
+ #
4
+ # Homepage:: http://whytheluckystiff.net/ruby/redcloth/
5
+ # Author:: why the lucky stiff (http://whytheluckystiff.net/)
6
+ # Copyright:: (cc) 2004 why the lucky stiff (and his puppet organizations.)
7
+ # License:: BSD
8
+ #
9
+ # (see http://hobix.com/textile/ for a Textile Reference.)
10
+ #
11
+ # Based on (and also inspired by) both:
12
+ #
13
+ # PyTextile: http://diveintomark.org/projects/textile/textile.py.txt
14
+ # Textism for PHP: http://www.textism.com/tools/textile/
15
+ #
16
+ #
17
+
18
+ # = RedCloth
19
+ #
20
+ # RedCloth is a Ruby library for converting Textile and/or Markdown
21
+ # into HTML. You can use either format, intermingled or separately.
22
+ # You can also extend RedCloth to honor your own custom text stylings.
23
+ #
24
+ # RedCloth users are encouraged to use Textile if they are generating
25
+ # HTML and to use Markdown if others will be viewing the plain text.
26
+ #
27
+ # == What is Textile?
28
+ #
29
+ # Textile is a simple formatting style for text
30
+ # documents, loosely based on some HTML conventions.
31
+ #
32
+ # == Sample Textile Text
33
+ #
34
+ # h2. This is a title
35
+ #
36
+ # h3. This is a subhead
37
+ #
38
+ # This is a bit of paragraph.
39
+ #
40
+ # bq. This is a blockquote.
41
+ #
42
+ # = Writing Textile
43
+ #
44
+ # A Textile document consists of paragraphs. Paragraphs
45
+ # can be specially formatted by adding a small instruction
46
+ # to the beginning of the paragraph.
47
+ #
48
+ # h[n]. Header of size [n].
49
+ # bq. Blockquote.
50
+ # # Numeric list.
51
+ # * Bulleted list.
52
+ #
53
+ # == Quick Phrase Modifiers
54
+ #
55
+ # Quick phrase modifiers are also included, to allow formatting
56
+ # of small portions of text within a paragraph.
57
+ #
58
+ # \_emphasis\_
59
+ # \_\_italicized\_\_
60
+ # \*strong\*
61
+ # \*\*bold\*\*
62
+ # ??citation??
63
+ # -deleted text-
64
+ # +inserted text+
65
+ # ^superscript^
66
+ # ~subscript~
67
+ # @code@
68
+ # %(classname)span%
69
+ #
70
+ # ==notextile== (leave text alone)
71
+ #
72
+ # == Links
73
+ #
74
+ # To make a hypertext link, put the link text in "quotation
75
+ # marks" followed immediately by a colon and the URL of the link.
76
+ #
77
+ # Optional: text in (parentheses) following the link text,
78
+ # but before the closing quotation mark, will become a Title
79
+ # attribute for the link, visible as a tool tip when a cursor is above it.
80
+ #
81
+ # Example:
82
+ #
83
+ # "This is a link (This is a title) ":http://www.textism.com
84
+ #
85
+ # Will become:
86
+ #
87
+ # <a href="http://www.textism.com" title="This is a title">This is a link</a>
88
+ #
89
+ # == Images
90
+ #
91
+ # To insert an image, put the URL for the image inside exclamation marks.
92
+ #
93
+ # Optional: text that immediately follows the URL in (parentheses) will
94
+ # be used as the Alt text for the image. Images on the web should always
95
+ # have descriptive Alt text for the benefit of readers using non-graphical
96
+ # browsers.
97
+ #
98
+ # Optional: place a colon followed by a URL immediately after the
99
+ # closing ! to make the image into a link.
100
+ #
101
+ # Example:
102
+ #
103
+ # !http://www.textism.com/common/textist.gif(Textist)!
104
+ #
105
+ # Will become:
106
+ #
107
+ # <img src="http://www.textism.com/common/textist.gif" alt="Textist" />
108
+ #
109
+ # With a link:
110
+ #
111
+ # !/common/textist.gif(Textist)!:http://textism.com
112
+ #
113
+ # Will become:
114
+ #
115
+ # <a href="http://textism.com"><img src="/common/textist.gif" alt="Textist" /></a>
116
+ #
117
+ # == Defining Acronyms
118
+ #
119
+ # HTML allows authors to define acronyms via the tag. The definition appears as a
120
+ # tool tip when a cursor hovers over the acronym. A crucial aid to clear writing,
121
+ # this should be used at least once for each acronym in documents where they appear.
122
+ #
123
+ # To quickly define an acronym in Textile, place the full text in (parentheses)
124
+ # immediately following the acronym.
125
+ #
126
+ # Example:
127
+ #
128
+ # ACLU(American Civil Liberties Union)
129
+ #
130
+ # Will become:
131
+ #
132
+ # <acronym title="American Civil Liberties Union">ACLU</acronym>
133
+ #
134
+ # == Adding Tables
135
+ #
136
+ # In Textile, simple tables can be added by seperating each column by
137
+ # a pipe.
138
+ #
139
+ # |a|simple|table|row|
140
+ # |And|Another|table|row|
141
+ #
142
+ # Attributes are defined by style definitions in parentheses.
143
+ #
144
+ # table(border:1px solid black).
145
+ # (background:#ddd;color:red). |{}| | | |
146
+ #
147
+ # == Using RedCloth
148
+ #
149
+ # RedCloth is simply an extension of the String class, which can handle
150
+ # Textile formatting. Use it like a String and output HTML with its
151
+ # RedCloth#to_html method.
152
+ #
153
+ # doc = RedCloth.new "
154
+ #
155
+ # h2. Test document
156
+ #
157
+ # Just a simple test."
158
+ #
159
+ # puts doc.to_html
160
+ #
161
+ # By default, RedCloth uses both Textile and Markdown formatting, with
162
+ # Textile formatting taking precedence. If you want to turn off Markdown
163
+ # formatting, to boost speed and limit the processor:
164
+ #
165
+ # class RedCloth::Textile.new( str )
166
+
167
+ class RedCloth < String
168
+
169
+ VERSION = '3.0.1'
170
+
171
+ #
172
+ # Two accessor for setting security restrictions.
173
+ #
174
+ # This is a nice thing if you're using RedCloth for
175
+ # formatting in public places (e.g. Wikis) where you
176
+ # don't want users to abuse HTML for bad things.
177
+ #
178
+ # If +:filter_html+ is set, HTML which wasn't
179
+ # created by the Textile processor will be escaped.
180
+ #
181
+ # If +:filter_styles+ is set, it will also disable
182
+ # the style markup specifier. ('{color: red}')
183
+ #
184
+ attr_accessor :filter_html, :filter_styles
185
+
186
+ #
187
+ # Accessor for toggling hard breaks.
188
+ #
189
+ # If +:hard_breaks+ is set, single newlines will
190
+ # be converted to HTML break tags. This is the
191
+ # default behavior for traditional RedCloth.
192
+ #
193
+ attr_accessor :hard_breaks
194
+
195
+ #
196
+ # Establishes the markup predence. Available rules include:
197
+ #
198
+ # == Textile Rules
199
+ #
200
+ # The following textile rules can be set individually. Or add the complete
201
+ # set of rules with the single :textile rule, which supplies the rule set in
202
+ # the following precedence:
203
+ #
204
+ # refs_textile:: Textile references (i.e. [hobix]http://hobix.com/)
205
+ # block_textile_table:: Textile table block structures
206
+ # block_textile_lists:: Textile list structures
207
+ # block_textile_prefix:: Textile blocks with prefixes (i.e. bq., h2., etc.)
208
+ # inline_textile_image:: Textile inline images
209
+ # inline_textile_link:: Textile inline links
210
+ # inline_textile_span:: Textile inline spans
211
+ # inline_textile_glyphs:: Textile entities (such as em-dashes and smart quotes)
212
+ #
213
+ # == Markdown
214
+ #
215
+ # refs_markdown:: Markdown references (for example: [hobix]: http://hobix.com/)
216
+ # block_markdown_setext:: Markdown setext headers
217
+ # block_markdown_atx:: Markdown atx headers
218
+ # block_markdown_rule:: Markdown horizontal rules
219
+ # block_markdown_bq:: Markdown blockquotes
220
+ # block_markdown_lists:: Markdown lists
221
+ # inline_markdown_link:: Markdown links
222
+ attr_accessor :rules
223
+
224
+ # Returns a new RedCloth object, based on _string_ and
225
+ # enforcing all the included _restrictions_.
226
+ #
227
+ # r = RedCloth.new( "h1. A <b>bold</b> man", [:filter_html] )
228
+ # r.to_html
229
+ # #=>"<h1>A &lt;b&gt;bold&lt;/b&gt; man</h1>"
230
+ #
231
+ def initialize( string, restrictions = [] )
232
+ restrictions.each { |r| method( "#{ r }=" ).call( true ) }
233
+ @rules = [:textile, :markdown]
234
+ super( string )
235
+ end
236
+
237
+ #
238
+ # Generates HTML from the Textile contents.
239
+ #
240
+ # r = RedCloth.new( "And then? She *fell*!" )
241
+ # r.to_html( true )
242
+ # #=>"And then? She <strong>fell</strong>!"
243
+ #
244
+ def to_html( *rules )
245
+ rules = @rules if rules.empty?
246
+ # make our working copy
247
+ text = self.dup
248
+
249
+ @urlrefs = {}
250
+ @shelf = []
251
+ textile_rules = [:refs_textile, :block_textile_table, :block_textile_lists,
252
+ :block_textile_prefix, :inline_textile_image, :inline_textile_link,
253
+ :inline_textile_code, :inline_textile_glyphs, :inline_textile_span]
254
+ markdown_rules = [:refs_markdown, :block_markdown_setext, :block_markdown_atx, :block_markdown_rule,
255
+ :block_markdown_bq, :block_markdown_lists,
256
+ :inline_markdown_reflink, :inline_markdown_link]
257
+ @rules = rules.collect do |rule|
258
+ case rule
259
+ when :markdown
260
+ markdown_rules
261
+ when :textile
262
+ textile_rules
263
+ else
264
+ rule
265
+ end
266
+ end.flatten
267
+
268
+ # standard clean up
269
+ incoming_entities text
270
+ clean_white_space text
271
+
272
+ # start processor
273
+ pre_list = rip_offtags text
274
+ refs text
275
+ blocks text
276
+ inline text
277
+ smooth_offtags text, pre_list
278
+
279
+ retrieve text
280
+
281
+ text.gsub!( /<\/?notextile>/, '' )
282
+ text.gsub!( /x%x%/, '&#38;' )
283
+ text.strip!
284
+ text
285
+
286
+ end
287
+
288
+ #######
289
+ private
290
+ #######
291
+ #
292
+ # Mapping of 8-bit ASCII codes to HTML numerical entity equivalents.
293
+ # (from PyTextile)
294
+ #
295
+ TEXTILE_TAGS =
296
+
297
+ [[128, 8364], [129, 0], [130, 8218], [131, 402], [132, 8222], [133, 8230],
298
+ [134, 8224], [135, 8225], [136, 710], [137, 8240], [138, 352], [139, 8249],
299
+ [140, 338], [141, 0], [142, 0], [143, 0], [144, 0], [145, 8216], [146, 8217],
300
+ [147, 8220], [148, 8221], [149, 8226], [150, 8211], [151, 8212], [152, 732],
301
+ [153, 8482], [154, 353], [155, 8250], [156, 339], [157, 0], [158, 0], [159, 376]].
302
+
303
+ collect! do |a, b|
304
+ [a.chr, ( b.zero? and "" or "&#{ b };" )]
305
+ end
306
+
307
+ #
308
+ # Regular expressions to convert to HTML.
309
+ #
310
+ A_HLGN = /(?:(?:<>|<|>|\=|[()]+)+)/
311
+ A_VLGN = /[\-^~]/
312
+ C_CLAS = '(?:\([^)]+\))'
313
+ C_LNGE = '(?:\[[^\]]+\])'
314
+ C_STYL = '(?:\{[^}]+\})'
315
+ S_CSPN = '(?:\\\\\d+)'
316
+ S_RSPN = '(?:/\d+)'
317
+ A = "(?:#{A_HLGN}?#{A_VLGN}?|#{A_VLGN}?#{A_HLGN}?)"
318
+ S = "(?:#{S_CSPN}?#{S_RSPN}|#{S_RSPN}?#{S_CSPN}?)"
319
+ C = "(?:#{C_CLAS}?#{C_STYL}?#{C_LNGE}?|#{C_STYL}?#{C_LNGE}?#{C_CLAS}?|#{C_LNGE}?#{C_STYL}?#{C_CLAS}?)"
320
+ # PUNCT = Regexp::quote( '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' )
321
+ PUNCT = Regexp::quote( '!"#$%&\'*+,-./:;=?@\\^_`|~' )
322
+ HYPERLINK = '(\S+?)([^\w\s/;=\?]*?)(?=\s|<|$)'
323
+
324
+ # Text markup tags, don't conflict with block tags
325
+ SIMPLE_HTML_TAGS = [
326
+ 'tt', 'b', 'i', 'big', 'small', 'em', 'strong', 'dfn', 'code',
327
+ 'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'a', 'img', 'br',
328
+ 'br', 'map', 'q', 'sub', 'sup', 'span', 'bdo'
329
+ ]
330
+
331
+ # Elements to handle
332
+ GLYPHS = [
333
+ # [ /([^\s\[{(>])?\'([dmst]\b|ll\b|ve\b|\s|:|$)/, '\1&#8217;\2' ], # single closing
334
+ [ /([^\s\[{(>])\'/, '\1&#8217;' ], # single closing
335
+ [ /\'(?=\s|s\b|[#{PUNCT}])/, '&#8217;' ], # single closing
336
+ [ /\'/, '&#8216;' ], # single opening
337
+ # [ /([^\s\[{(])?"(\s|:|$)/, '\1&#8221;\2' ], # double closing
338
+ [ /([^\s\[{(>])"/, '\1&#8221;' ], # double closing
339
+ [ /"(?=\s|[#{PUNCT}])/, '&#8221;' ], # double closing
340
+ [ /"/, '&#8220;' ], # double opening
341
+ [ /\b( )?\.{3}/, '\1&#8230;' ], # ellipsis
342
+ [ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '<acronym title="\2">\1</acronym>' ], # 3+ uppercase acronym
343
+ [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]{2,})([^<a-z0-9]|$)/, '\1<span class="caps">\2</span>\3' ], # 3+ uppercase caps
344
+ [ /(\.\s)?\s?--\s?/, '\1&#8212;' ], # em dash
345
+ [ /\s->\s/, ' &rarr; ' ], # right arrow
346
+ [ /\s-\s/, ' &#8211; ' ], # en dash
347
+ [ /(\d+) ?x ?(\d+)/, '\1&#215;\2' ], # dimension sign
348
+ [ /\b ?[(\[]TM[\])]/i, '&#8482;' ], # trademark
349
+ [ /\b ?[(\[]R[\])]/i, '&#174;' ], # registered
350
+ [ /\b ?[(\[]C[\])]/i, '&#169;' ] # copyright
351
+ ]
352
+
353
+ H_ALGN_VALS = {
354
+ '<' => 'left',
355
+ '=' => 'center',
356
+ '>' => 'right',
357
+ '<>' => 'justify'
358
+ }
359
+
360
+ V_ALGN_VALS = {
361
+ '^' => 'top',
362
+ '-' => 'middle',
363
+ '~' => 'bottom'
364
+ }
365
+
366
+ QTAGS = [
367
+ ['**', 'b'],
368
+ ['*', 'strong'],
369
+ ['??', 'cite'],
370
+ ['-', 'del'],
371
+ ['__', 'i'],
372
+ ['_', 'em'],
373
+ ['%', 'span'],
374
+ ['+', 'ins'],
375
+ ['^', 'sup'],
376
+ ['~', 'sub']
377
+ ]
378
+ QTAGS_RE = /(#{ QTAGS.collect { |rc, ht| Regexp::quote( rc ) }.join( '|' ) })
379
+ (#{C})
380
+ (?::(\S+?))?
381
+ ([^\s\1]+?(?:[^\n]|\n(?!\n))*?)
382
+ \1/xm
383
+
384
+ #
385
+ # Flexible HTML escaping
386
+ #
387
+ def htmlesc( str, mode )
388
+ str.gsub!( '&', '&amp;' )
389
+ str.gsub!( '"', '&quot;' ) if mode != :NoQuotes
390
+ str.gsub!( "'", '&#039;' ) if mode == :Quotes
391
+ str.gsub!( '<', '&lt;')
392
+ str.gsub!( '>', '&gt;')
393
+ end
394
+
395
+ # Search and replace for Textile glyphs (quotes, dashes, other symbols)
396
+ def pgl( text )
397
+ GLYPHS.each do |re, resub|
398
+ text.gsub! re, resub
399
+ end
400
+ end
401
+
402
+ # Parses Textile attribute lists and builds an HTML attribute string
403
+ def pba( text_in, element = "" )
404
+
405
+ return '' unless text_in
406
+
407
+ style = []
408
+ text = text_in.dup
409
+ if element == 'td'
410
+ colspan = $1 if text =~ /\\(\d+)/
411
+ rowspan = $1 if text =~ /\/(\d+)/
412
+ style << "vertical-align:#{ v_align( $& ) };" if text =~ A_VLGN
413
+ end
414
+
415
+ style << "#{ $1 };" if not @filter_styles and
416
+ text.sub!( /\{([^}]*)\}/, '' )
417
+
418
+ lang = $1 if
419
+ text.sub!( /\[([^)]+?)\]/, '' )
420
+
421
+ cls = $1 if
422
+ text.sub!( /\(([^()]+?)\)/, '' )
423
+
424
+ style << "padding-left:#{ $1.length }em;" if
425
+ text.sub!( /([(]+)/, '' )
426
+
427
+ style << "padding-right:#{ $1.length }em;" if text.sub!( /([)]+)/, '' )
428
+
429
+ style << "text-align:#{ h_align( $& ) };" if text =~ A_HLGN
430
+
431
+ cls, id = $1, $2 if cls =~ /^(.*?)#(.*)$/
432
+
433
+ atts = ''
434
+ atts << " style=\"#{ style.join }\"" unless style.empty?
435
+ atts << " class=\"#{ cls }\"" unless cls.to_s.empty?
436
+ atts << " lang=\"#{ lang }\"" if lang
437
+ atts << " id=\"#{ id }\"" if id
438
+ atts << " colspan=\"#{ colspan }\"" if colspan
439
+ atts << " rowspan=\"#{ rowspan }\"" if rowspan
440
+
441
+ atts
442
+ end
443
+
444
+ TABLE_RE = /^(?:table(_?#{S}#{A}#{C})\. ?\n)?^(#{A}#{C}\.? ?\|.*?\|)(\n\n|\Z)/m
445
+
446
+ # Parses a Textile table block, building HTML from the result.
447
+ def block_textile_table( text )
448
+ text.gsub!( TABLE_RE ) do |matches|
449
+
450
+ tatts, fullrow = $~[1..2]
451
+ tatts = pba( tatts, 'table' )
452
+ tatts = shelve( tatts ) if tatts
453
+ rows = []
454
+
455
+ fullrow.
456
+ split( /\|$/m ).
457
+ delete_if { |x| x.empty? }.
458
+ each do |row|
459
+
460
+ ratts, row = pba( $1, 'tr' ), $2 if row =~ /^(#{A}#{C}\. )(.*)/m
461
+
462
+ cells = []
463
+ row.split( '|' ).each do |cell|
464
+ ctyp = 'd'
465
+ ctyp = 'h' if cell =~ /^_/
466
+
467
+ catts = ''
468
+ catts, cell = pba( $1, 'td' ), $2 if cell =~ /^(_?#{S}#{A}#{C}\. ?)(.*)/
469
+
470
+ unless cell.strip.empty?
471
+ catts = shelve( catts ) if catts
472
+ cells << "\t\t\t<t#{ ctyp }#{ catts }>#{ cell }</t#{ ctyp }>"
473
+ end
474
+ end
475
+ ratts = shelve( ratts ) if ratts
476
+ rows << "\t\t<tr#{ ratts }>\n#{ cells.join( "\n" ) }\n\t\t</tr>"
477
+ end
478
+ "\t<table#{ tatts }>\n#{ rows.join( "\n" ) }\n\t</table>\n\n"
479
+ end
480
+ end
481
+
482
+ LISTS_RE = /^([#*]+?#{C} .*?)$(?![^#*])/m
483
+ LISTS_CONTENT_RE = /^([#*]+)(#{A}#{C}) (.*)$/m
484
+
485
+ # Parses Textile lists and generates HTML
486
+ def block_textile_lists( text )
487
+ text.gsub!( LISTS_RE ) do |match|
488
+ lines = match.split( /\n/ )
489
+ last_line = -1
490
+ depth = []
491
+ lines.each_with_index do |line, line_id|
492
+ if line =~ LISTS_CONTENT_RE
493
+ tl,atts,content = $~[1..3]
494
+ if depth.last
495
+ if depth.last.length > tl.length
496
+ (depth.length - 1).downto(0) do |i|
497
+ break if depth[i].length == tl.length
498
+ lines[line_id - 1] << "</li>\n\t</#{ lT( depth[i] ) }l>\n\t"
499
+ depth.pop
500
+ end
501
+ end
502
+ if depth.last.length == tl.length
503
+ lines[line_id - 1] << '</li>'
504
+ end
505
+ end
506
+ unless depth.last == tl
507
+ depth << tl
508
+ atts = pba( atts )
509
+ atts = shelve( atts ) if atts
510
+ lines[line_id] = "\t<#{ lT(tl) }l#{ atts }>\n\t<li>#{ content }"
511
+ else
512
+ lines[line_id] = "\t\t<li>#{ content }"
513
+ end
514
+ last_line = line_id
515
+
516
+ else
517
+ last_line = line_id
518
+ end
519
+ if line_id - last_line > 1 or line_id == lines.length - 1
520
+ depth.delete_if do |v|
521
+ lines[last_line] << "</li>\n\t</#{ lT( v ) }l>"
522
+ end
523
+ end
524
+ end
525
+ lines.join( "\n" )
526
+ end
527
+ end
528
+
529
+ CODE_RE = /
530
+ (^|[\s>#{PUNCT}{(\[]) # 1 open bracket?
531
+ @ # opening
532
+ (?:\|(\w+?)\|)? # 2 language
533
+ (\S(?:[^\n]|\n(?!\n))*?) # 3 code
534
+ @ # closing
535
+ (?=[\s\]}\)<#{PUNCT}]|$) # 4 closing bracket?
536
+ /x
537
+
538
+ def inline_textile_code( text )
539
+ text.gsub!( CODE_RE ) do |m|
540
+ before,lang,code,after = $~[1..4]
541
+ lang = " lang=\"#{ lang }\"" if lang
542
+ "#{ before }<code#{ lang }>#{ code }</code>#{ after }"
543
+ end
544
+ end
545
+
546
+ def lT( text )
547
+ text =~ /\#$/ ? 'o' : 'u'
548
+ end
549
+
550
+ def hard_break( text )
551
+ text.gsub!( /(.)\n(?! *[#*\s|])/, "\\1<br />" ) if @hard_breaks
552
+ end
553
+
554
+ BLOCKS_GROUP_RE = /((?:\n*([#*> ])(?:[^\n]|\n+\2|\n(?!\n|\Z))+))|((?:[^\n]+|\n+ +|\n(?![#*\n]|\Z))+)/m
555
+
556
+ def blocks( text, deep_code = false )
557
+ text.gsub!( BLOCKS_GROUP_RE ) do |blk|
558
+ plain = $3 ? true : false
559
+
560
+ # skip blocks that are complex HTML
561
+ if blk =~ /^<\/?(\w+).*>/ and not SIMPLE_HTML_TAGS.include? $1
562
+ blk
563
+ else
564
+ # search for indentation levels
565
+ blk.strip!
566
+ if blk.empty?
567
+ blk
568
+ else
569
+ code_blk = nil
570
+ blk.gsub!( /((?:\n(?:\n^ +[^\n]*)+)+)/m ) do |iblk|
571
+ flush_left iblk
572
+ blocks iblk, plain
573
+ iblk.gsub( /^(\S)/, "\t\\1" )
574
+ if plain
575
+ code_blk = iblk; ""
576
+ else
577
+ iblk
578
+ end
579
+ end
580
+
581
+ block_applied = nil
582
+ @rules.each do |rule_name|
583
+ break if block_applied = ( rule_name.to_s.match /^block_/ and method( rule_name ).call( blk ) )
584
+ end
585
+ unless block_applied
586
+ if deep_code
587
+ blk = "\t<pre><code>#{ blk }</code></pre>"
588
+ else
589
+ blk = "\t<p>#{ blk }</p>"
590
+ end
591
+ end
592
+ # hard_break blk
593
+ blk + "\n#{ code_blk }"
594
+ end
595
+ end
596
+
597
+ end
598
+ end
599
+
600
+ def textile_bq( tag, atts, cite, content )
601
+ cite, cite_title = check_refs( cite )
602
+ cite = " cite=\"#{ cite }\"" if cite
603
+ atts = shelve( atts ) if atts
604
+ "\t<blockquote#{ cite }>\n\t\t<p#{ atts }>#{ content }</p>\n\t</blockquote>"
605
+ end
606
+
607
+ def textile_p( tag, atts, cite, content )
608
+ atts = shelve( atts ) if atts
609
+ "\t<#{ tag }#{ atts }>#{ content }</#{ tag }>"
610
+ end
611
+
612
+ alias textile_h1 textile_p
613
+ alias textile_h2 textile_p
614
+ alias textile_h3 textile_p
615
+ alias textile_h4 textile_p
616
+ alias textile_h5 textile_p
617
+ alias textile_h6 textile_p
618
+
619
+ def textile_fn_( tag, num, atts, cite, content )
620
+ atts << " id=\"fn#{ num }\""
621
+ content = "<sup>#{ num }</sup> #{ content }"
622
+ atts = shelve( atts ) if atts
623
+ "\t<p#{ atts }>#{ content }</p>"
624
+ end
625
+
626
+ BLOCK_RE = /^(([a-z]+)(\d*))(#{A}#{C})\.(?::(\S+))? (.*)$/m
627
+
628
+ def block_textile_prefix( text )
629
+ if text =~ BLOCK_RE
630
+ tag,tagpre,num,atts,cite,content = $~[1..6]
631
+ atts = pba( atts )
632
+
633
+ # pass to prefix handler
634
+ if respond_to? "textile_#{ tag }", true
635
+ text.gsub!( $&, method( "textile_#{ tag }" ).call( tag, atts, cite, content ) )
636
+ elsif respond_to? "textile_#{ tagpre }_", true
637
+ text.gsub!( $&, method( "textile_#{ tagpre }_" ).call( tagpre, num, atts, cite, content ) )
638
+ end
639
+ end
640
+ end
641
+
642
+ SETEXT_RE = /\A(.+?)\n([=-])[=-]* *$/m
643
+ def block_markdown_setext( text )
644
+ if text =~ SETEXT_RE
645
+ tag = if $2 == "="; "h1"; else; "h2"; end
646
+ blk, cont = "<#{ tag }>#{ $1 }</#{ tag }>", $'
647
+ blocks cont
648
+ text.replace( blk + cont )
649
+ end
650
+ end
651
+
652
+ ATX_RE = /\A(\#{1,6}) # $1 = string of #'s
653
+ [ ]*
654
+ (.+?) # $2 = Header text
655
+ [ ]*
656
+ \#* # optional closing #'s (not counted)
657
+ $/x
658
+ def block_markdown_atx( text )
659
+ if text =~ ATX_RE
660
+ tag = "h#{ $1.length }"
661
+ blk, cont = "<#{ tag }>#{ $2 }</#{ tag }>\n\n", $'
662
+ blocks cont
663
+ text.replace( blk + cont )
664
+ end
665
+ end
666
+
667
+ MARKDOWN_BQ_RE = /\A(^ *> ?.+$(.+\n)*\n*)+/m
668
+
669
+ def block_markdown_bq( text )
670
+ text.gsub!( MARKDOWN_BQ_RE ) do |blk|
671
+ blk.gsub!( /^ *> ?/, '' )
672
+ flush_left blk
673
+ blocks blk
674
+ blk.gsub!( /^(\S)/, "\t\\1" )
675
+ "<blockquote>\n#{ blk }\n</blockquote>\n\n"
676
+ end
677
+ end
678
+
679
+ MARKDOWN_RULE_RE = /^#{
680
+ ['*', '-', '_'].collect { |ch| '( ?' + Regexp::quote( ch ) + ' ?){3,}' }.join( '|' )
681
+ }$/
682
+
683
+ def block_markdown_rule( text )
684
+ text.gsub!( MARKDOWN_RULE_RE ) do |blk|
685
+ "<hr />"
686
+ end
687
+ end
688
+
689
+ # XXX TODO XXX
690
+ def block_markdown_lists( text )
691
+ end
692
+
693
+ def inline_markdown_link( text )
694
+ end
695
+
696
+ def inline_textile_span( text )
697
+ text.gsub!( QTAGS_RE ) do |m|
698
+
699
+ qtag,atts,cite,content = $~[1..4]
700
+ ht = QTAGS.assoc( qtag ).last
701
+ atts = pba( atts )
702
+ atts << " cite=\"#{ cite }\"" if cite
703
+ atts = shelve( atts ) if atts
704
+
705
+ "<#{ ht }#{ atts }>#{ content }</#{ ht }>"
706
+
707
+ end
708
+ end
709
+
710
+ LINK_RE = /
711
+ ([\s\[{(]|[#{PUNCT}])? # $pre
712
+ " # start
713
+ (#{C}) # $atts
714
+ ([^"]+?) # $text
715
+ \s?
716
+ (?:\(([^)]+?)\)(?="))? # $title
717
+ ":
718
+ (\S+?) # $url
719
+ (\/)? # $slash
720
+ ([^\w\/;]*?) # $post
721
+ (?=<|\s|$)
722
+ /x
723
+
724
+ def inline_textile_link( text )
725
+ text.gsub!( LINK_RE ) do |m|
726
+ pre,atts,text,title,url,slash,post = $~[1..7]
727
+
728
+ url, url_title = check_refs( url )
729
+ title ||= url_title
730
+
731
+ atts = pba( atts )
732
+ atts = " href=\"#{ url }#{ slash }\"#{ atts }"
733
+ atts << " title=\"#{ title }\"" if title
734
+ atts = shelve( atts ) if atts
735
+
736
+ "#{ pre }<a#{ atts }>#{ text }</a>#{ post }"
737
+ end
738
+ end
739
+
740
+ MARKDOWN_REFLINK_RE = /
741
+ \[([^\[\]]+)\] # $text
742
+ [ ]? # opt. space
743
+ (?:\n[ ]*)? # one optional newline followed by spaces
744
+ \[(.*?)\] # $id
745
+ /x
746
+
747
+ def inline_markdown_reflink( text )
748
+ text.gsub!( MARKDOWN_REFLINK_RE ) do |m|
749
+ text, id = $~[1..2]
750
+
751
+ if id.empty?
752
+ url, title = check_refs( text )
753
+ else
754
+ url, title = check_refs( id )
755
+ end
756
+
757
+ atts = " href=\"#{ url }\""
758
+ atts << " title=\"#{ title }\"" if title
759
+ atts = shelve( atts )
760
+
761
+ "<a#{ atts }>#{ text }</a>"
762
+ end
763
+ end
764
+
765
+ MARKDOWN_LINK_RE = /
766
+ \[([^\[\]]+)\] # $text
767
+ \( # open paren
768
+ [ \t]* # opt space
769
+ <?(.+?)>? # $href
770
+ [ \t]* # opt space
771
+ (?: # whole title
772
+ (['"]) # $quote
773
+ (.*?) # $title
774
+ \3 # matching quote
775
+ )? # title is optional
776
+ \)
777
+ /x
778
+
779
+ def inline_markdown_link( text )
780
+ text.gsub!( MARKDOWN_LINK_RE ) do |m|
781
+ text, url, quote, title = $~[1..4]
782
+
783
+ atts = " href=\"#{ url }\""
784
+ atts << " title=\"#{ title }\"" if title
785
+ atts = shelve( atts )
786
+
787
+ "<a#{ atts }>#{ text }</a>"
788
+ end
789
+ end
790
+
791
+ TEXTILE_REFS_RE = /(^ *)\[([^\n]+?)\](#{HYPERLINK})(?=\s|$)/
792
+ MARKDOWN_REFS_RE = /(^ *)\[([^\n]+?)\]:\s+<?(#{HYPERLINK})>?(?:\s+"((?:[^"]|\\")+)")?(?=\s|$)/m
793
+
794
+ def refs( text )
795
+ @rules.each do |rule_name|
796
+ method( rule_name ).call( text ) if rule_name.to_s.match /^refs_/
797
+ end
798
+ end
799
+
800
+ def refs_textile( text )
801
+ text.gsub!( TEXTILE_REFS_RE ) do |m|
802
+ flag, url = $~[2..3]
803
+ @urlrefs[flag.downcase] = [url, nil]
804
+ nil
805
+ end
806
+ end
807
+
808
+ def refs_markdown( text )
809
+ text.gsub!( MARKDOWN_REFS_RE ) do |m|
810
+ flag, url = $~[2..3]
811
+ title = $~[6]
812
+ @urlrefs[flag.downcase] = [url, title]
813
+ nil
814
+ end
815
+ end
816
+
817
+ def check_refs( text )
818
+ ret = @urlrefs[text.downcase] if text
819
+ ret || [text, nil]
820
+ end
821
+
822
+ IMAGE_RE = /
823
+ (<p>|.|^) # start of line?
824
+ \! # opening
825
+ (\<|\=|\>)? # optional alignment atts
826
+ (#{C}) # optional style,class atts
827
+ (?:\. )? # optional dot-space
828
+ ([^\s(!]+?) # presume this is the src
829
+ \s? # optional space
830
+ (?:\(((?:[^\(\)]|\([^\)]+\))+?)\))? # optional title
831
+ \! # closing
832
+ (?::#{ HYPERLINK })? # optional href
833
+ /x
834
+
835
+ def inline_textile_image( text )
836
+ text.gsub!( IMAGE_RE ) do |m|
837
+ stln,algn,atts,url,title,href,href_a1,href_a2 = $~[1..8]
838
+ atts = pba( atts )
839
+ atts = " src=\"#{ url }\"#{ atts }"
840
+ atts << " title=\"#{ title }\"" if title
841
+ atts << " alt=\"#{ title }\""
842
+ # size = @getimagesize($url);
843
+ # if($size) $atts.= " $size[3]";
844
+
845
+ href, alt_title = check_refs( href ) if href
846
+ url, url_title = check_refs( url )
847
+
848
+ out = ''
849
+ out << "<a#{ shelve( " href=\"#{ href }\"" ) }>" if href
850
+ out << "<img#{ shelve( atts ) } />"
851
+ out << "</a>#{ href_a1 }#{ href_a2 }" if href
852
+
853
+ if algn
854
+ algn = h_align( algn )
855
+ if stln == "<p>"
856
+ out = "<p style=\"float:#{ algn }\">#{ out }"
857
+ else
858
+ out = "#{ stln }<div style=\"float:#{ algn }\">#{ out }</div>"
859
+ end
860
+ else
861
+ out = stln + out
862
+ end
863
+
864
+ out
865
+ end
866
+ end
867
+
868
+ def shelve( val )
869
+ @shelf << val
870
+ " <#{ @shelf.length }>"
871
+ end
872
+
873
+ def retrieve( text )
874
+ @shelf.each_with_index do |r, i|
875
+ text.gsub!( " <#{ i + 1 }>", r )
876
+ end
877
+ end
878
+
879
+ def incoming_entities( text )
880
+ ## turn any incoming ampersands into a dummy character for now.
881
+ ## This uses a negative lookahead for alphanumerics followed by a semicolon,
882
+ ## implying an incoming html entity, to be skipped
883
+
884
+ text.gsub!( /&(?![#a-z0-9]+;)/i, "x%x%" )
885
+ end
886
+
887
+ def no_textile( text )
888
+ text.gsub!( /(^|\s)==(.*?)==(\s|$)?/,
889
+ '\1<notextile>\2</notextile>\3' )
890
+ text.gsub!( /^ *==(.*?)==/m,
891
+ '\1<notextile>\2</notextile>\3' )
892
+ end
893
+
894
+ def clean_white_space( text )
895
+ # normalize line breaks
896
+ text.gsub!( /\r\n/, "\n" )
897
+ text.gsub!( /\r/, "\n" )
898
+ text.gsub!( /\t/, ' ' )
899
+ text.gsub!( /^ +$/, '' )
900
+ text.gsub!( /\n{3,}/, "\n\n" )
901
+ text.gsub!( /"$/, "\" " )
902
+
903
+ # if entire document is indented, flush
904
+ # to the left side
905
+ flush_left text
906
+ end
907
+
908
+ def flush_left( text )
909
+ indt = 0
910
+ while text !~ /^ {#{indt}}\S/
911
+ indt += 1
912
+ end
913
+ if indt.nonzero?
914
+ text.gsub!( /^ {#{indt}}/, '' )
915
+ end
916
+ end
917
+
918
+ def footnote_ref( text )
919
+ text.gsub!( /\b\[([0-9]+?)\](\s)?/,
920
+ '<sup><a href="#fn\1">\1</a></sup>\2' )
921
+ end
922
+
923
+ OFFTAGS = /(code|pre|kbd|notextile)/
924
+ OFFTAG_MATCH = /(?:(<\/#{ OFFTAGS }>)|(<#{ OFFTAGS }[^>]*>))(.*?)(?=<\/?#{ OFFTAGS }|\Z)/mi
925
+ OFFTAG_OPEN = /<#{ OFFTAGS }/
926
+ OFFTAG_CLOSE = /<\/?#{ OFFTAGS }/
927
+ HASTAG_MATCH = /(<\/?\w[^\n]*?>)/m
928
+ ALLTAG_MATCH = /(<\/?\w[^\n]*?>)|.*?(?=<\/?\w[^\n]*?>|$)/m
929
+
930
+ def inline_textile_glyphs( text, level = 0 )
931
+ if text !~ HASTAG_MATCH
932
+ pgl text
933
+ footnote_ref text
934
+ else
935
+ codepre = 0
936
+ text.gsub!( ALLTAG_MATCH ) do |line|
937
+ ## matches are off if we're between <code>, <pre> etc.
938
+ if $1
939
+ if @filter_html
940
+ htmlesc( line, :NoQuotes )
941
+ elsif line =~ OFFTAG_OPEN
942
+ codepre += 1
943
+ elsif line =~ OFFTAG_CLOSE
944
+ codepre -= 1
945
+ codepre = 0 if codepre < 0
946
+ end
947
+ elsif codepre.zero?
948
+ inline_textile_glyphs( line, level + 1 )
949
+ else
950
+ htmlesc( line, :NoQuotes )
951
+ end
952
+ ## p [level, codepre, orig_line, line]
953
+
954
+ line
955
+ end
956
+ end
957
+ end
958
+
959
+ def rip_offtags( text )
960
+ pre_list = []
961
+ if text =~ /<.*>/
962
+ ## strip and encode <pre> content
963
+ codepre, used_offtags = 0, {}
964
+ text.gsub!( OFFTAG_MATCH ) do |line|
965
+ if $3
966
+ offtag, aftertag = $4, $5
967
+ codepre += 1
968
+ used_offtags[offtag] = true
969
+ if codepre - used_offtags.length > 0
970
+ htmlesc( line, :NoQuotes ) unless used_offtags['notextile']
971
+ pre_list.last << line
972
+ line = ""
973
+ else
974
+ htmlesc( aftertag, :NoQuotes ) if aftertag and not used_offtags['notextile']
975
+ line = "<redpre##{ pre_list.length }>"
976
+ pre_list << "#{ $3 }#{ aftertag }"
977
+ end
978
+ elsif $1 and codepre > 0
979
+ if codepre - used_offtags.length > 0
980
+ htmlesc( line, :NoQuotes ) unless used_offtags['notextile']
981
+ pre_list.last << line
982
+ line = ""
983
+ end
984
+ codepre -= 1 unless codepre.zero?
985
+ used_offtags = {} if codepre.zero?
986
+ end
987
+ line
988
+ end
989
+ end
990
+ pre_list
991
+ end
992
+
993
+ def smooth_offtags( text, pre_list )
994
+ unless pre_list.empty?
995
+ ## replace <pre> content
996
+ text.gsub!( /<redpre#(\d+)>/ ) { pre_list[$1.to_i] }
997
+ end
998
+ end
999
+
1000
+ def inline( text )
1001
+ @rules.each do |rule_name|
1002
+ method( rule_name ).call( text ) if rule_name.to_s.match /^inline_/
1003
+ end
1004
+ end
1005
+
1006
+ def h_align( text )
1007
+ H_ALGN_VALS[text]
1008
+ end
1009
+
1010
+ def v_align( text )
1011
+ V_ALGN_VALS[text]
1012
+ end
1013
+
1014
+ def textile_popup_help( name, windowW, windowH )
1015
+ ' <a target="_blank" href="http://hobix.com/textile/#' + helpvar + '" onclick="window.open(this.href, \'popupwindow\', \'width=' + windowW + ',height=' + windowH + ',scrollbars,resizable\'); return false;">' + name + '</a><br />'
1016
+ end
1017
+
1018
+ end
1019
+