Soks 0.0.2

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.
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
+