Pimki 1.3.092 → 1.4.092

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/README +145 -131
  2. data/README-PIMKI +15 -5
  3. data/app/controllers/wiki.rb +167 -54
  4. data/app/models/author.rb +3 -3
  5. data/app/models/chunks/chunk.rb +3 -3
  6. data/app/models/chunks/engines.rb +18 -21
  7. data/app/models/chunks/include.rb +29 -29
  8. data/app/models/chunks/literal.rb +20 -20
  9. data/app/models/chunks/match.rb +19 -19
  10. data/app/models/chunks/nowiki.rb +31 -31
  11. data/app/models/chunks/nowiki_test.rb +14 -14
  12. data/app/models/chunks/test.rb +18 -18
  13. data/app/models/chunks/todo.rb +44 -23
  14. data/app/models/chunks/uri.rb +97 -97
  15. data/app/models/chunks/uri_test.rb +92 -92
  16. data/app/models/chunks/wiki.rb +4 -4
  17. data/app/models/chunks/wiki_symbols.rb +22 -22
  18. data/app/models/chunks/wiki_test.rb +36 -36
  19. data/app/models/page.rb +39 -7
  20. data/app/models/page_lock.rb +23 -23
  21. data/app/models/page_set.rb +72 -72
  22. data/app/models/page_test.rb +75 -75
  23. data/app/models/revision.rb +1 -1
  24. data/app/models/revision_test.rb +251 -251
  25. data/app/models/web.rb +19 -6
  26. data/app/models/web_test.rb +52 -52
  27. data/app/models/wiki_content.rb +131 -119
  28. data/app/models/wiki_service.rb +31 -16
  29. data/app/models/wiki_service_test.rb +15 -15
  30. data/app/models/wiki_words.rb +1 -1
  31. data/app/models/wiki_words_test.rb +12 -12
  32. data/app/views/bottom.rhtml +3 -3
  33. data/app/views/markdown_help.rhtml +15 -15
  34. data/app/views/menu.rhtml +20 -20
  35. data/app/views/navigation.rhtml +26 -26
  36. data/app/views/rdoc_help.rhtml +15 -15
  37. data/app/views/static_style_sheet.rhtml +237 -237
  38. data/app/views/style.rhtml +178 -178
  39. data/app/views/textile_help.rhtml +27 -27
  40. data/app/views/top.rhtml +7 -2
  41. data/app/views/wiki/authors.rhtml +15 -15
  42. data/app/views/wiki/bliki.rhtml +101 -101
  43. data/app/views/wiki/bliki_edit.rhtml +3 -0
  44. data/app/views/wiki/bliki_new.rhtml +3 -0
  45. data/app/views/wiki/bliki_revision.rhtml +90 -90
  46. data/app/views/wiki/edit.rhtml +12 -3
  47. data/app/views/wiki/edit_menu.rhtml +64 -47
  48. data/app/views/wiki/edit_web.rhtml +65 -18
  49. data/app/views/wiki/export.rhtml +14 -14
  50. data/app/views/wiki/feeds.rhtml +10 -10
  51. data/app/views/wiki/list.rhtml +17 -15
  52. data/app/views/wiki/locked.rhtml +13 -13
  53. data/app/views/wiki/login.rhtml +10 -10
  54. data/app/views/wiki/mind.rhtml +0 -1
  55. data/app/views/wiki/new.rhtml +8 -3
  56. data/app/views/wiki/new_system.rhtml +77 -77
  57. data/app/views/wiki/new_web.rhtml +63 -63
  58. data/app/views/wiki/page.rhtml +88 -82
  59. data/app/views/wiki/print.rhtml +15 -15
  60. data/app/views/wiki/published.rhtml +2 -1
  61. data/app/views/wiki/recently_revised.rhtml +31 -31
  62. data/app/views/wiki/revision.rhtml +1 -7
  63. data/app/views/wiki/rollback.rhtml +31 -0
  64. data/app/views/wiki/rss_feed.rhtml +21 -21
  65. data/app/views/wiki/search.rhtml +48 -48
  66. data/app/views/wiki/tex.rhtml +22 -22
  67. data/app/views/wiki/tex_web.rhtml +34 -34
  68. data/app/views/wiki/todo.rhtml +90 -67
  69. data/app/views/wiki/web_list.rhtml +12 -12
  70. data/app/views/wiki_words_help.rhtml +1 -1
  71. data/favicon.png +0 -0
  72. data/libraries/action_controller_servlet.rb +17 -2
  73. data/libraries/bluecloth.rb +1127 -1127
  74. data/libraries/diff/diff.rb +474 -474
  75. data/libraries/diff/diff_test.rb +79 -79
  76. data/libraries/erb.rb +490 -490
  77. data/libraries/madeleine/automatic.rb +418 -357
  78. data/libraries/madeleine/clock.rb +94 -94
  79. data/libraries/madeleine/files.rb +19 -0
  80. data/libraries/madeleine/zmarshal.rb +60 -0
  81. data/libraries/madeleine_service.rb +14 -15
  82. data/libraries/rdocsupport.rb +155 -155
  83. data/libraries/redcloth_for_tex.rb +869 -869
  84. data/libraries/redcloth_for_tex_test.rb +40 -40
  85. data/libraries/view_helper.rb +32 -32
  86. data/libraries/web_controller_server.rb +96 -94
  87. data/pimki.rb +47 -6
  88. metadata +18 -4
@@ -1,869 +1,869 @@
1
- # vim:ts=4:sw=4:
2
- # = RedCloth - Textile for Ruby
3
- #
4
- # (c) 2003 why the lucky stiff (and his puppet organizations.)
5
- #
6
- # (see http://www.textism.com/tools/textile/ for Textile)
7
- #
8
- # Based on (and also inspired by) both:
9
- #
10
- # PyTextile: http://diveintomark.org/projects/textile/textile.py.txt
11
- # Textism for PHP: http://www.textism.com/tools/textile/
12
- #
13
- #
14
- # == What is Textile?
15
- #
16
- # Textile is a simple formatting style for text
17
- # documents, loosely based on some HTML conventions.
18
- #
19
- # === Sample Textile Text
20
- #
21
- # h2. This is a title
22
- #
23
- # h3. This is a subhead
24
- #
25
- # This is a bit of paragraph.
26
- #
27
- # bq. This is a blockquote.
28
- #
29
- # === Writing Textile
30
- #
31
- # A Textile document consists of paragraphs. Paragraphs
32
- # can be specially formatted by adding a small instruction
33
- # to the beginning of the paragraph.
34
- #
35
- # h[n]. Header of size [n].
36
- # bq. Blockquote.
37
- # # Numeric list.
38
- # * Bulleted list.
39
- #
40
- # === Quick Phrase Modifiers
41
- #
42
- # Quick phrase modifiers are also included, to allow formatting
43
- # of small portions of text within a paragraph.
44
- #
45
- # _emphasis_
46
- # __italicized__
47
- # *strong*
48
- # **bold**
49
- # ??citation??
50
- # -deleted text-
51
- # +inserted text+
52
- # ^superscript^
53
- # ~subscript~
54
- # @code@
55
- # %(classname)span%
56
- #
57
- # ==notextile== (leave text alone)
58
- #
59
- # === Links
60
- #
61
- # To make a hypertext link, put the link text in "quotation
62
- # marks" followed immediately by a colon and the URL of the link.
63
- #
64
- # Optional: text in (parentheses) following the link text,
65
- # but before the closing quotation mark, will become a Title
66
- # attribute for the link, visible as a tool tip when a cursor is above it.
67
- #
68
- # Example:
69
- #
70
- # "This is a link (This is a title) ":http://www.textism.com
71
- #
72
- # Will become:
73
- #
74
- # <a href="http://www.textism.com" title="This is a title">This is a link</a>
75
- #
76
- # === Images
77
- #
78
- # To insert an image, put the URL for the image inside exclamation marks.
79
- #
80
- # Optional: text that immediately follows the URL in (parentheses) will
81
- # be used as the Alt text for the image. Images on the web should always
82
- # have descriptive Alt text for the benefit of readers using non-graphical
83
- # browsers.
84
- #
85
- # Optional: place a colon followed by a URL immediately after the
86
- # closing ! to make the image into a link.
87
- #
88
- # Example:
89
- #
90
- # !http://www.textism.com/common/textist.gif(Textist)!
91
- #
92
- # Will become:
93
- #
94
- # <img src="http://www.textism.com/common/textist.gif" alt="Textist" />
95
- #
96
- # With a link:
97
- #
98
- # !/common/textist.gif(Textist)!:http://textism.com
99
- #
100
- # Will become:
101
- #
102
- # <a href="http://textism.com"><img src="/common/textist.gif" alt="Textist" /></a>
103
- #
104
- # === Defining Acronyms
105
- #
106
- # HTML allows authors to define acronyms via the tag. The definition appears as a
107
- # tool tip when a cursor hovers over the acronym. A crucial aid to clear writing,
108
- # this should be used at least once for each acronym in documents where they appear.
109
- #
110
- # To quickly define an acronym in Textile, place the full text in (parentheses)
111
- # immediately following the acronym.
112
- #
113
- # Example:
114
- #
115
- # ACLU(American Civil Liberties Union)
116
- #
117
- # Will become:
118
- #
119
- # <acronym title="American Civil Liberties Union">ACLU</acronym>
120
- #
121
- # === Adding Tables
122
- #
123
- # In Textile, simple tables can be added by seperating each column by
124
- # a pipe.
125
- #
126
- # |a|simple|table|row|
127
- # |And|Another|table|row|
128
- #
129
- # Attributes are defined by style definitions in parentheses.
130
- #
131
- # table(border:1px solid black).
132
- # (background:#ddd;color:red). |{}| | | |
133
- #
134
- # === Using RedCloth
135
- #
136
- # RedCloth is simply an extension of the String class, which can handle
137
- # Textile formatting. Use it like a String and output HTML with its
138
- # RedCloth#to_html method.
139
- #
140
- # doc = RedCloth.new "
141
- #
142
- # h2. Test document
143
- #
144
- # Just a simple test."
145
- #
146
- # puts doc.to_html
147
-
148
- class String
149
- #
150
- # Flexible HTML escaping
151
- #
152
- def texesc!( mode )
153
- gsub!( '&', '\\\\&' )
154
- gsub!( '%', '\%' )
155
- gsub!( '$', '\$' )
156
- end
157
- end
158
-
159
-
160
- def table_of_contents(text, pages)
161
- text.gsub!( /^([#*]+? .*?)$(?![^#*])/m ) do |match|
162
- lines = match.split( /\n/ )
163
- last_line = -1
164
- depth = []
165
- lines.each_with_index do |line, line_id|
166
- if line =~ /^([#*]+) (.*)$/m
167
- tl,content = $~[1..2]
168
- content.gsub! /[\[\]]/, ""
169
- content.strip!
170
-
171
- if depth.last
172
- if depth.last.length > tl.length
173
- (depth.length - 1).downto(0) do |i|
174
- break if depth[i].length == tl.length
175
- lines[line_id - 1] << "" # "\n\t\\end{#{ lT( depth[i] ) }}\n\t"
176
- depth.pop
177
- end
178
- end
179
- if !depth.last.nil? && !tl.length.nil? && depth.last.length == tl.length
180
- lines[line_id - 1] << ''
181
- end
182
- end
183
-
184
- depth << tl unless depth.last == tl
185
-
186
- subsection_depth = [depth.length - 1, 2].min
187
-
188
- lines[line_id] = "\n\\#{ "sub" * subsection_depth }section{#{ content }}"
189
- lines[line_id] += "\n#{pages[content]}" if pages.keys.include?(content)
190
-
191
- lines[line_id] = "\\pagebreak\n#{lines[line_id]}" if subsection_depth == 0
192
-
193
- last_line = line_id
194
-
195
- elsif line =~ /^\s+\S/
196
- last_line = line_id
197
- elsif line_id - last_line < 2 and line =~ /^\S/
198
- last_line = line_id
199
- end
200
- if line_id - last_line > 1 or line_id == lines.length - 1
201
- depth.delete_if do |v|
202
- lines[last_line] << "" # "\n\t\\end{#{ lT( v ) }}"
203
- end
204
- end
205
- end
206
- lines.join( "\n" )
207
- end
208
- end
209
-
210
- class RedClothForTex < String
211
-
212
- VERSION = '2.0.7'
213
-
214
- #
215
- # Mapping of 8-bit ASCII codes to HTML numerical entity equivalents.
216
- # (from PyTextile)
217
- #
218
- TEXTILE_TAGS =
219
-
220
- [[128, 8364], [129, 0], [130, 8218], [131, 402], [132, 8222], [133, 8230],
221
- [134, 8224], [135, 8225], [136, 710], [137, 8240], [138, 352], [139, 8249],
222
- [140, 338], [141, 0], [142, 0], [143, 0], [144, 0], [145, 8216], [146, 8217],
223
- [147, 8220], [148, 8221], [149, 8226], [150, 8211], [151, 8212], [152, 732],
224
- [153, 8482], [154, 353], [155, 8250], [156, 339], [157, 0], [158, 0], [159, 376]].
225
-
226
- collect! do |a, b|
227
- [a.chr, ( b.zero? and "" or "&#{ b };" )]
228
- end
229
-
230
- #
231
- # Regular expressions to convert to HTML.
232
- #
233
- A_HLGN = /(?:(?:<>|<|>|\=|[()]+)+)/
234
- A_VLGN = /[\-^~]/
235
- C_CLAS = '(?:\([^)]+\))'
236
- C_LNGE = '(?:\[[^\]]+\])'
237
- C_STYL = '(?:\{[^}]+\})'
238
- S_CSPN = '(?:\\\\\d+)'
239
- S_RSPN = '(?:/\d+)'
240
- A = "(?:#{A_HLGN}?#{A_VLGN}?|#{A_VLGN}?#{A_HLGN}?)"
241
- S = "(?:#{S_CSPN}?#{S_RSPN}|#{S_RSPN}?#{S_CSPN}?)"
242
- C = "(?:#{C_CLAS}?#{C_STYL}?#{C_LNGE}?|#{C_STYL}?#{C_LNGE}?#{C_CLAS}?|#{C_LNGE}?#{C_STYL}?#{C_CLAS}?)"
243
- # PUNCT = Regexp::quote( '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' )
244
- PUNCT = Regexp::quote( '!"#$%&\'*+,-./:;=?@\\^_`|~' )
245
- HYPERLINK = '(\S+?)([^\w\s/;=\?]*?)(\s|$)'
246
-
247
- GLYPHS = [
248
- # [ /([^\s\[{(>])?\'([dmst]\b|ll\b|ve\b|\s|:|$)/, '\1&#8217;\2' ], # single closing
249
- [ /([^\s\[{(>])\'/, '\1&#8217;' ], # single closing
250
- [ /\'(?=\s|s\b|[#{PUNCT}])/, '&#8217;' ], # single closing
251
- [ /\'/, '&#8216;' ], # single opening
252
- # [ /([^\s\[{(])?"(\s|:|$)/, '\1&#8221;\2' ], # double closing
253
- [ /([^\s\[{(>])"/, '\1&#8221;' ], # double closing
254
- [ /"(?=\s|[#{PUNCT}])/, '&#8221;' ], # double closing
255
- [ /"/, '&#8220;' ], # double opening
256
- [ /\b( )?\.{3}/, '\1&#8230;' ], # ellipsis
257
- [ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '<acronym title="\2">\1</acronym>' ], # 3+ uppercase acronym
258
- [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]{2,})([^<a-z0-9]|$)/, '\1<span class="caps">\2</span>\3' ], # 3+ uppercase caps
259
- [ /(\.\s)?\s?--\s?/, '\1&#8212;' ], # em dash
260
- [ /\s->\s/, ' &rarr; ' ], # en dash
261
- [ /\s-\s/, ' &#8211; ' ], # en dash
262
- [ /(\d+) ?x ?(\d+)/, '\1&#215;\2' ], # dimension sign
263
- [ /\b ?[(\[]TM[\])]/i, '&#8482;' ], # trademark
264
- [ /\b ?[(\[]R[\])]/i, '&#174;' ], # registered
265
- [ /\b ?[(\[]C[\])]/i, '&#169;' ] # copyright
266
- ]
267
-
268
- I_ALGN_VALS = {
269
- '<' => 'left',
270
- '=' => 'center',
271
- '>' => 'right'
272
- }
273
-
274
- H_ALGN_VALS = {
275
- '<' => 'left',
276
- '=' => 'center',
277
- '>' => 'right',
278
- '<>' => 'justify'
279
- }
280
-
281
- V_ALGN_VALS = {
282
- '^' => 'top',
283
- '-' => 'middle',
284
- '~' => 'bottom'
285
- }
286
-
287
- QTAGS = [
288
- ['**', 'bf'],
289
- ['*', 'bf'],
290
- ['??', 'cite'],
291
- ['-', 'del'],
292
- ['__', 'underline'],
293
- ['_', 'em'],
294
- ['%', 'span'],
295
- ['+', 'ins'],
296
- ['^', 'sup'],
297
- ['~', 'sub']
298
- ]
299
-
300
- #
301
- # Two accessor for setting security restrictions.
302
- #
303
- # This is a nice thing if you're using RedCloth for
304
- # formatting in public places (e.g. Wikis) where you
305
- # don't want users to abuse HTML for bad things.
306
- #
307
- # If +:filter_html+ is set, HTML which wasn't
308
- # created by the Textile processor will be escaped.
309
- #
310
- # If +:filter_styles+ is set, it will also disable
311
- # the style markup specifier. ('{color: red}')
312
- #
313
- attr_accessor :filter_html, :filter_styles
314
-
315
- #
316
- # Accessor for toggling line folding.
317
- #
318
- # If +:fold_lines+ is set, single newlines will
319
- # not be converted to break tags.
320
- #
321
- attr_accessor :fold_lines
322
-
323
- def initialize( string, restrictions = [] )
324
- restrictions.each { |r| method( "#{ r }=" ).call( true ) }
325
- super( string )
326
- end
327
-
328
- #
329
- # Generate tex.
330
- #
331
- def to_tex( lite = false )
332
-
333
- # make our working copy
334
- text = self.dup
335
-
336
- @urlrefs = {}
337
- @shelf = []
338
-
339
- # incoming_entities text
340
- fix_entities text
341
- clean_white_space text
342
-
343
- get_refs text
344
-
345
- no_textile text
346
-
347
- unless lite
348
- lists text
349
- table text
350
- end
351
-
352
- glyphs text
353
-
354
- unless lite
355
- fold text
356
- block text
357
- end
358
-
359
- retrieve text
360
- encode_entities text
361
-
362
- text.gsub!(/\[\[(.*?)\]\]/, "\\1")
363
- text.gsub!(/_/, "\\_")
364
- text.gsub!( /<\/?notextile>/, '' )
365
- # text.gsub!( /x%x%/, '&#38;' )
366
- # text.gsub!( /<br \/>/, "<br />\n" )
367
- text.strip!
368
- text
369
-
370
- end
371
-
372
- def pgl( text )
373
- GLYPHS.each do |re, resub|
374
- text.gsub! re, resub
375
- end
376
- end
377
-
378
- def pba( text_in, element = "" )
379
-
380
- return '' unless text_in
381
-
382
- style = []
383
- text = text_in.dup
384
- if element == 'td'
385
- colspan = $1 if text =~ /\\(\d+)/
386
- rowspan = $1 if text =~ /\/(\d+)/
387
- style << "vertical-align:#{ v_align( $& ) };" if text =~ A_VLGN
388
- end
389
-
390
- style << "#{ $1 };" if not @filter_styles and
391
- text.sub!( /\{([^}]*)\}/, '' )
392
-
393
- lang = $1 if
394
- text.sub!( /\[([^)]+?)\]/, '' )
395
-
396
- cls = $1 if
397
- text.sub!( /\(([^()]+?)\)/, '' )
398
-
399
- style << "padding-left:#{ $1.length }em;" if
400
- text.sub!( /([(]+)/, '' )
401
-
402
- style << "padding-right:#{ $1.length }em;" if text.sub!( /([)]+)/, '' )
403
-
404
- style << "text-align:#{ h_align( $& ) };" if text =~ A_HLGN
405
-
406
- cls, id = $1, $2 if cls =~ /^(.*?)#(.*)$/
407
-
408
- atts = ''
409
- atts << " style=\"#{ style.join }\"" unless style.empty?
410
- atts << " class=\"#{ cls }\"" unless cls.to_s.empty?
411
- atts << " lang=\"#{ lang }\"" if lang
412
- atts << " id=\"#{ id }\"" if id
413
- atts << " colspan=\"#{ colspan }\"" if colspan
414
- atts << " rowspan=\"#{ rowspan }\"" if rowspan
415
-
416
- atts
417
- end
418
-
419
- def table( text )
420
- text << "\n\n"
421
- text.gsub!( /^(?:table(_?#{S}#{A}#{C})\. ?\n)?^(#{A}#{C}\.? ?\|.*?\|)\n\n/m ) do |matches|
422
-
423
- tatts, fullrow = $~[1..2]
424
- tatts = pba( tatts, 'table' )
425
- rows = []
426
-
427
- fullrow.
428
- split( /\|$/m ).
429
- delete_if { |x| x.empty? }.
430
- each do |row|
431
-
432
- ratts, row = pba( $1, 'tr' ), $2 if row =~ /^(#{A}#{C}\. )(.*)/m
433
-
434
- cells = []
435
- row.split( '|' ).each do |cell|
436
- ctyp = 'd'
437
- ctyp = 'h' if cell =~ /^_/
438
-
439
- catts = ''
440
- catts, cell = pba( $1, 'td' ), $2 if cell =~ /^(_?#{S}#{A}#{C}\. )(.*)/
441
-
442
- unless cell.strip.empty?
443
- cells << "\t\t\t<t#{ ctyp }#{ catts }>#{ cell }</t#{ ctyp }>"
444
- end
445
- end
446
- rows << "\t\t<tr#{ ratts }>\n#{ cells.join( "\n" ) }\n\t\t</tr>"
447
- end
448
- "\t<table#{ tatts }>\n#{ rows.join( "\n" ) }\n\t</table>\n\n"
449
- end
450
- end
451
-
452
- def lists( text )
453
- text.gsub!( /^([#*]+?#{C} .*?)$(?![^#*])/m ) do |match|
454
- lines = match.split( /\n/ )
455
- last_line = -1
456
- depth = []
457
- lines.each_with_index do |line, line_id|
458
- if line =~ /^([#*]+)(#{A}#{C}) (.*)$/m
459
- tl,atts,content = $~[1..3]
460
- if depth.last
461
- if depth.last.length > tl.length
462
- (depth.length - 1).downto(0) do |i|
463
- break if depth[i].length == tl.length
464
- lines[line_id - 1] << "\n\t\\end{#{ lT( depth[i] ) }}\n\t"
465
- depth.pop
466
- end
467
- end
468
- if !depth.last.nil? && !tl.length.nil? && depth.last.length == tl.length
469
- lines[line_id - 1] << ''
470
- end
471
- end
472
- unless depth.last == tl
473
- depth << tl
474
- atts = pba( atts )
475
- lines[line_id] = "\t\\begin{#{ lT(tl) }}\n\t\\item #{ content }"
476
- else
477
- lines[line_id] = "\t\t\\item #{ content }"
478
- end
479
- last_line = line_id
480
-
481
- elsif line =~ /^\s+\S/
482
- last_line = line_id
483
- elsif line_id - last_line < 2 and line =~ /^\S/
484
- last_line = line_id
485
- end
486
- if line_id - last_line > 1 or line_id == lines.length - 1
487
- depth.delete_if do |v|
488
- lines[last_line] << "\n\t\\end{#{ lT( v ) }}"
489
- end
490
- end
491
- end
492
- lines.join( "\n" )
493
- end
494
- end
495
-
496
- def lT( text )
497
- text =~ /\#$/ ? 'enumerate' : 'itemize'
498
- end
499
-
500
- def fold( text )
501
- text.gsub!( /(.+)\n(?![#*\s|])/, "\\1\\\\\\\\" )
502
- # text.gsub!( /(.+)\n(?![#*\s|])/, "\\1#{ @fold_lines ? ' ' : '<br />' }" )
503
- end
504
-
505
- def block( text )
506
- pre = false
507
- find = ['bq','h[1-6]','fn\d+']
508
-
509
- regexp_cue = []
510
-
511
- lines = text.split( /\n/ ) + [' ']
512
- new_text =
513
- lines.collect do |line|
514
- pre = true if line =~ /<(pre|notextile)>/i
515
- find.each do |tag|
516
- line.gsub!( /^(#{ tag })(#{A}#{C})\.(?::(\S+))? (.*)$/ ) do |m|
517
- tag,atts,cite,content = $~[1..4]
518
-
519
- atts = pba( atts )
520
-
521
- if tag =~ /fn(\d+)/
522
- # tag = 'p';
523
- # atts << " id=\"fn#{ $1 }\""
524
- regexp_cue << [ /footnote\{#{$1}}/, "footnote{#{content}}" ]
525
- content = ""
526
- end
527
-
528
- if tag =~ /h([1-6])/
529
- section_type = "sub" * [$1.to_i - 1, 2].min
530
- start = "\t\\#{section_type}section*{"
531
- tend = "}"
532
- end
533
-
534
- if tag == "bq"
535
- cite = check_refs( cite )
536
- cite = " cite=\"#{ cite }\"" if cite
537
- start = "\t\\begin{quotation}\n\\noindent {\\em ";
538
- tend = "}\n\t\\end{quotation}";
539
- end
540
-
541
- "#{ start }#{ content }#{ tend }"
542
- end unless pre
543
- end
544
-
545
- #line.gsub!( /^(?!\t|<\/?pre|<\/?notextile|<\/?code|$| )(.*)/, "\t<p>\\1</p>" )
546
-
547
- #line.gsub!( "<br />", "\n" ) if pre
548
- # pre = false if line =~ /<\/(pre|notextile)>/i
549
-
550
- line
551
- end.join( "\n" )
552
- text.replace( new_text )
553
- regexp_cue.each { |pair| text.gsub!(pair.first, pair.last) }
554
- end
555
-
556
- def span( text )
557
- QTAGS.each do |tt, ht|
558
- ttr = Regexp::quote( tt )
559
- text.gsub!(
560
-
561
- /(^|\s|\>|[#{PUNCT}{(\[])
562
- #{ttr}
563
- (#{C})
564
- (?::(\S+?))?
565
- ([^\s#{ttr}]+?(?:[^\n]|\n(?!\n))*?)
566
- ([#{PUNCT}]*?)
567
- #{ttr}
568
- (?=[\])}]|[#{PUNCT}]+?|<|\s|$)/xm
569
-
570
- ) do |m|
571
-
572
- start,atts,cite,content,tend = $~[1..5]
573
- atts = pba( atts )
574
- atts << " cite=\"#{ cite }\"" if cite
575
-
576
- "#{ start }{\\#{ ht } #{ content }#{ tend }}"
577
-
578
- end
579
- end
580
- end
581
-
582
- def links( text )
583
- text.gsub!( /
584
- ([\s\[{(]|[#{PUNCT}])? # $pre
585
- " # start
586
- (#{C}) # $atts
587
- ([^"]+?) # $text
588
- \s?
589
- (?:\(([^)]+?)\)(?="))? # $title
590
- ":
591
- (\S+?) # $url
592
- (\/)? # $slash
593
- ([^\w\/;]*?) # $post
594
- (?=\s|$)
595
- /x ) do |m|
596
- pre,atts,text,title,url,slash,post = $~[1..7]
597
-
598
- url = check_refs( url )
599
-
600
- atts = pba( atts )
601
- atts << " title=\"#{ title }\"" if title
602
- atts = shelve( atts ) if atts
603
-
604
- "#{ pre }<a href=\"#{ url }#{ slash }\"#{ atts }>#{ text }</a>#{ post }"
605
- end
606
- end
607
-
608
- def get_refs( text )
609
- text.gsub!( /(^|\s)\[(.+?)\]((?:http:\/\/|javascript:|ftp:\/\/|\/)\S+?)(?=\s|$)/ ) do |m|
610
- flag, url = $~[1..2]
611
- @urlrefs[flag] = url
612
- end
613
- end
614
-
615
- def check_refs( text )
616
- @urlrefs[text] || text
617
- end
618
-
619
- def image( text )
620
- text.gsub!( /
621
- \! # opening
622
- (\<|\=|\>)? # optional alignment atts
623
- (#{C}) # optional style,class atts
624
- (?:\. )? # optional dot-space
625
- ([^\s(!]+?) # presume this is the src
626
- \s? # optional space
627
- (?:\(((?:[^\(\)]|\([^\)]+\))+?)\))? # optional title
628
- \! # closing
629
- (?::#{ HYPERLINK })? # optional href
630
- /x ) do |m|
631
- algn,atts,url,title,href,href_a1,href_a2 = $~[1..7]
632
- atts = pba( atts )
633
- atts << " align=\"#{ i_align( algn ) }\"" if algn
634
- atts << " title=\"#{ title }\"" if title
635
- atts << " alt=\"#{ title }\""
636
- # size = @getimagesize($url);
637
- # if($size) $atts.= " $size[3]";
638
-
639
- href = check_refs( href ) if href
640
- url = check_refs( url )
641
-
642
- out = ''
643
- out << "<a href=\"#{ href }\">" if href
644
- out << "<img src=\"#{ url }\"#{ atts } />"
645
- out << "</a>#{ href_a1 }#{ href_a2 }" if href
646
-
647
- out
648
- end
649
- end
650
-
651
- def code( text )
652
- text.gsub!( /
653
- (?:^|([\s\(\[{])) # 1 open bracket?
654
- @ # opening
655
- (?:\|(\w+?)\|)? # 2 language
656
- (\S(?:[^\n]|\n(?!\n))*?) # 3 code
657
- @ # closing
658
- (?:$|([\]})])|
659
- (?=[#{PUNCT}]{1,2}|
660
- \s)) # 4 closing bracket?
661
- /x ) do |m|
662
- before,lang,code,after = $~[1..4]
663
- lang = " language=\"#{ lang }\"" if lang
664
- "#{ before }<code#{ lang }>#{ code }</code>#{ after }"
665
- end
666
- end
667
-
668
- def shelve( val )
669
- @shelf << val
670
- " <#{ @shelf.length }>"
671
- end
672
-
673
- def retrieve( text )
674
- @shelf.each_with_index do |r, i|
675
- text.gsub!( " <#{ i + 1 }>", r )
676
- end
677
- end
678
-
679
- def incoming_entities( text )
680
- ## turn any incoming ampersands into a dummy character for now.
681
- ## This uses a negative lookahead for alphanumerics followed by a semicolon,
682
- ## implying an incoming html entity, to be skipped
683
-
684
- text.gsub!( /&(?![#a-z0-9]+;)/i, "x%x%" )
685
- end
686
-
687
- def encode_entities( text )
688
- ## Convert high and low ascii to entities.
689
- # if $-K == "UTF-8"
690
- # encode_high( text )
691
- # else
692
- text.texesc!( :NoQuotes )
693
- # end
694
- end
695
-
696
- def fix_entities( text )
697
- ## de-entify any remaining angle brackets or ampersands
698
- text.gsub!( "\&", "&" )
699
- text.gsub!( "\%", "%" )
700
- end
701
-
702
- def clean_white_space( text )
703
- text.gsub!( /\r\n/, "\n" )
704
- text.gsub!( /\t/, '' )
705
- text.gsub!( /\n{3,}/, "\n\n" )
706
- text.gsub!( /\n *\n/, "\n\n" )
707
- text.gsub!( /"$/, "\" " )
708
- end
709
-
710
- def no_textile( text )
711
- text.gsub!( /(^|\s)==(.*?)==(\s|$)?/,
712
- '\1<notextile>\2</notextile>\3' )
713
- end
714
-
715
- def footnote_ref( text )
716
- text.gsub!( /\[([0-9]+?)\](\s)?/,
717
- '\footnote{\1}\2')
718
- #'<sup><a href="#fn\1">\1</a></sup>\2' )
719
- end
720
-
721
- def inline( text )
722
- image text
723
- links text
724
- code text
725
- span text
726
- end
727
-
728
- def glyphs_deep( text )
729
- codepre = 0
730
- offtags = /(?:code|pre|kbd|notextile)/
731
- if text !~ /<.*>/
732
- # pgl text
733
- footnote_ref text
734
- else
735
- used_offtags = {}
736
- text.gsub!( /(?:[^<].*?(?=<[^\n]*?>|$)|<[^\n]*?>+)/m ) do |line|
737
- tagline = ( line =~ /^<.*>/ )
738
-
739
- ## matches are off if we're between <code>, <pre> etc.
740
- if tagline
741
- if line =~ /<(#{ offtags })>/i
742
- codepre += 1
743
- used_offtags[$1] = true
744
- line.texesc!( :NoQuotes ) if codepre - used_offtags.length > 0
745
- elsif line =~ /<\/(#{ offtags })>/i
746
- line.texesc!( :NoQuotes ) if codepre - used_offtags.length > 0
747
- codepre -= 1 unless codepre.zero?
748
- used_offtags = {} if codepre.zero?
749
- elsif @filter_html or codepre > 0
750
- line.texesc!( :NoQuotes )
751
- ## line.gsub!( /&lt;(\/?#{ offtags })&gt;/, '<\1>' )
752
- end
753
- ## do htmlspecial if between <code>
754
- elsif codepre > 0
755
- line.texesc!( :NoQuotes )
756
- ## line.gsub!( /&lt;(\/?#{ offtags })&gt;/, '<\1>' )
757
- elsif not tagline
758
- inline line
759
- glyphs_deep line
760
- end
761
-
762
- line
763
- end
764
- end
765
- end
766
-
767
- def glyphs( text )
768
- text.gsub!( /"\z/, "\" " )
769
- ## if no html, do a simple search and replace...
770
- if text !~ /<.*>/
771
- inline text
772
- end
773
- glyphs_deep text
774
- end
775
-
776
- def i_align( text )
777
- I_ALGN_VALS[text]
778
- end
779
-
780
- def h_align( text )
781
- H_ALGN_VALS[text]
782
- end
783
-
784
- def v_align( text )
785
- V_ALGN_VALS[text]
786
- end
787
-
788
- def encode_high( text )
789
- ## mb_encode_numericentity($text, $cmap, $charset);
790
- end
791
-
792
- def decode_high( text )
793
- ## mb_decode_numericentity($text, $cmap, $charset);
794
- end
795
-
796
- def textile_popup_help( name, helpvar, windowW, windowH )
797
- ' <a target="_blank" href="http://www.textpattern.com/help/?item=' + helpvar + '" onclick="window.open(this.href, \'popupwindow\', \'width=' + windowW + ',height=' + windowH + ',scrollbars,resizable\'); return false;">' + name + '</a><br />'
798
- end
799
-
800
- CMAP = [
801
- 160, 255, 0, 0xffff,
802
- 402, 402, 0, 0xffff,
803
- 913, 929, 0, 0xffff,
804
- 931, 937, 0, 0xffff,
805
- 945, 969, 0, 0xffff,
806
- 977, 978, 0, 0xffff,
807
- 982, 982, 0, 0xffff,
808
- 8226, 8226, 0, 0xffff,
809
- 8230, 8230, 0, 0xffff,
810
- 8242, 8243, 0, 0xffff,
811
- 8254, 8254, 0, 0xffff,
812
- 8260, 8260, 0, 0xffff,
813
- 8465, 8465, 0, 0xffff,
814
- 8472, 8472, 0, 0xffff,
815
- 8476, 8476, 0, 0xffff,
816
- 8482, 8482, 0, 0xffff,
817
- 8501, 8501, 0, 0xffff,
818
- 8592, 8596, 0, 0xffff,
819
- 8629, 8629, 0, 0xffff,
820
- 8656, 8660, 0, 0xffff,
821
- 8704, 8704, 0, 0xffff,
822
- 8706, 8707, 0, 0xffff,
823
- 8709, 8709, 0, 0xffff,
824
- 8711, 8713, 0, 0xffff,
825
- 8715, 8715, 0, 0xffff,
826
- 8719, 8719, 0, 0xffff,
827
- 8721, 8722, 0, 0xffff,
828
- 8727, 8727, 0, 0xffff,
829
- 8730, 8730, 0, 0xffff,
830
- 8733, 8734, 0, 0xffff,
831
- 8736, 8736, 0, 0xffff,
832
- 8743, 8747, 0, 0xffff,
833
- 8756, 8756, 0, 0xffff,
834
- 8764, 8764, 0, 0xffff,
835
- 8773, 8773, 0, 0xffff,
836
- 8776, 8776, 0, 0xffff,
837
- 8800, 8801, 0, 0xffff,
838
- 8804, 8805, 0, 0xffff,
839
- 8834, 8836, 0, 0xffff,
840
- 8838, 8839, 0, 0xffff,
841
- 8853, 8853, 0, 0xffff,
842
- 8855, 8855, 0, 0xffff,
843
- 8869, 8869, 0, 0xffff,
844
- 8901, 8901, 0, 0xffff,
845
- 8968, 8971, 0, 0xffff,
846
- 9001, 9002, 0, 0xffff,
847
- 9674, 9674, 0, 0xffff,
848
- 9824, 9824, 0, 0xffff,
849
- 9827, 9827, 0, 0xffff,
850
- 9829, 9830, 0, 0xffff,
851
- 338, 339, 0, 0xffff,
852
- 352, 353, 0, 0xffff,
853
- 376, 376, 0, 0xffff,
854
- 710, 710, 0, 0xffff,
855
- 732, 732, 0, 0xffff,
856
- 8194, 8195, 0, 0xffff,
857
- 8201, 8201, 0, 0xffff,
858
- 8204, 8207, 0, 0xffff,
859
- 8211, 8212, 0, 0xffff,
860
- 8216, 8218, 0, 0xffff,
861
- 8218, 8218, 0, 0xffff,
862
- 8220, 8222, 0, 0xffff,
863
- 8224, 8225, 0, 0xffff,
864
- 8240, 8240, 0, 0xffff,
865
- 8249, 8250, 0, 0xffff,
866
- 8364, 8364, 0, 0xffff
867
- ]
868
- end
869
-
1
+ # vim:ts=4:sw=4:
2
+ # = RedCloth - Textile for Ruby
3
+ #
4
+ # (c) 2003 why the lucky stiff (and his puppet organizations.)
5
+ #
6
+ # (see http://www.textism.com/tools/textile/ for Textile)
7
+ #
8
+ # Based on (and also inspired by) both:
9
+ #
10
+ # PyTextile: http://diveintomark.org/projects/textile/textile.py.txt
11
+ # Textism for PHP: http://www.textism.com/tools/textile/
12
+ #
13
+ #
14
+ # == What is Textile?
15
+ #
16
+ # Textile is a simple formatting style for text
17
+ # documents, loosely based on some HTML conventions.
18
+ #
19
+ # === Sample Textile Text
20
+ #
21
+ # h2. This is a title
22
+ #
23
+ # h3. This is a subhead
24
+ #
25
+ # This is a bit of paragraph.
26
+ #
27
+ # bq. This is a blockquote.
28
+ #
29
+ # === Writing Textile
30
+ #
31
+ # A Textile document consists of paragraphs. Paragraphs
32
+ # can be specially formatted by adding a small instruction
33
+ # to the beginning of the paragraph.
34
+ #
35
+ # h[n]. Header of size [n].
36
+ # bq. Blockquote.
37
+ # # Numeric list.
38
+ # * Bulleted list.
39
+ #
40
+ # === Quick Phrase Modifiers
41
+ #
42
+ # Quick phrase modifiers are also included, to allow formatting
43
+ # of small portions of text within a paragraph.
44
+ #
45
+ # _emphasis_
46
+ # __italicized__
47
+ # *strong*
48
+ # **bold**
49
+ # ??citation??
50
+ # -deleted text-
51
+ # +inserted text+
52
+ # ^superscript^
53
+ # ~subscript~
54
+ # @code@
55
+ # %(classname)span%
56
+ #
57
+ # ==notextile== (leave text alone)
58
+ #
59
+ # === Links
60
+ #
61
+ # To make a hypertext link, put the link text in "quotation
62
+ # marks" followed immediately by a colon and the URL of the link.
63
+ #
64
+ # Optional: text in (parentheses) following the link text,
65
+ # but before the closing quotation mark, will become a Title
66
+ # attribute for the link, visible as a tool tip when a cursor is above it.
67
+ #
68
+ # Example:
69
+ #
70
+ # "This is a link (This is a title) ":http://www.textism.com
71
+ #
72
+ # Will become:
73
+ #
74
+ # <a href="http://www.textism.com" title="This is a title">This is a link</a>
75
+ #
76
+ # === Images
77
+ #
78
+ # To insert an image, put the URL for the image inside exclamation marks.
79
+ #
80
+ # Optional: text that immediately follows the URL in (parentheses) will
81
+ # be used as the Alt text for the image. Images on the web should always
82
+ # have descriptive Alt text for the benefit of readers using non-graphical
83
+ # browsers.
84
+ #
85
+ # Optional: place a colon followed by a URL immediately after the
86
+ # closing ! to make the image into a link.
87
+ #
88
+ # Example:
89
+ #
90
+ # !http://www.textism.com/common/textist.gif(Textist)!
91
+ #
92
+ # Will become:
93
+ #
94
+ # <img src="http://www.textism.com/common/textist.gif" alt="Textist" />
95
+ #
96
+ # With a link:
97
+ #
98
+ # !/common/textist.gif(Textist)!:http://textism.com
99
+ #
100
+ # Will become:
101
+ #
102
+ # <a href="http://textism.com"><img src="/common/textist.gif" alt="Textist" /></a>
103
+ #
104
+ # === Defining Acronyms
105
+ #
106
+ # HTML allows authors to define acronyms via the tag. The definition appears as a
107
+ # tool tip when a cursor hovers over the acronym. A crucial aid to clear writing,
108
+ # this should be used at least once for each acronym in documents where they appear.
109
+ #
110
+ # To quickly define an acronym in Textile, place the full text in (parentheses)
111
+ # immediately following the acronym.
112
+ #
113
+ # Example:
114
+ #
115
+ # ACLU(American Civil Liberties Union)
116
+ #
117
+ # Will become:
118
+ #
119
+ # <acronym title="American Civil Liberties Union">ACLU</acronym>
120
+ #
121
+ # === Adding Tables
122
+ #
123
+ # In Textile, simple tables can be added by seperating each column by
124
+ # a pipe.
125
+ #
126
+ # |a|simple|table|row|
127
+ # |And|Another|table|row|
128
+ #
129
+ # Attributes are defined by style definitions in parentheses.
130
+ #
131
+ # table(border:1px solid black).
132
+ # (background:#ddd;color:red). |{}| | | |
133
+ #
134
+ # === Using RedCloth
135
+ #
136
+ # RedCloth is simply an extension of the String class, which can handle
137
+ # Textile formatting. Use it like a String and output HTML with its
138
+ # RedCloth#to_html method.
139
+ #
140
+ # doc = RedCloth.new "
141
+ #
142
+ # h2. Test document
143
+ #
144
+ # Just a simple test."
145
+ #
146
+ # puts doc.to_html
147
+
148
+ class String
149
+ #
150
+ # Flexible HTML escaping
151
+ #
152
+ def texesc!( mode )
153
+ gsub!( '&', '\\\\&' )
154
+ gsub!( '%', '\%' )
155
+ gsub!( '$', '\$' )
156
+ end
157
+ end
158
+
159
+
160
+ def table_of_contents(text, pages)
161
+ text.gsub!( /^([#*]+? .*?)$(?![^#*])/m ) do |match|
162
+ lines = match.split( /\n/ )
163
+ last_line = -1
164
+ depth = []
165
+ lines.each_with_index do |line, line_id|
166
+ if line =~ /^([#*]+) (.*)$/m
167
+ tl,content = $~[1..2]
168
+ content.gsub! /[\[\]]/, ""
169
+ content.strip!
170
+
171
+ if depth.last
172
+ if depth.last.length > tl.length
173
+ (depth.length - 1).downto(0) do |i|
174
+ break if depth[i].length == tl.length
175
+ lines[line_id - 1] << "" # "\n\t\\end{#{ lT( depth[i] ) }}\n\t"
176
+ depth.pop
177
+ end
178
+ end
179
+ if !depth.last.nil? && !tl.length.nil? && depth.last.length == tl.length
180
+ lines[line_id - 1] << ''
181
+ end
182
+ end
183
+
184
+ depth << tl unless depth.last == tl
185
+
186
+ subsection_depth = [depth.length - 1, 2].min
187
+
188
+ lines[line_id] = "\n\\#{ "sub" * subsection_depth }section{#{ content }}"
189
+ lines[line_id] += "\n#{pages[content]}" if pages.keys.include?(content)
190
+
191
+ lines[line_id] = "\\pagebreak\n#{lines[line_id]}" if subsection_depth == 0
192
+
193
+ last_line = line_id
194
+
195
+ elsif line =~ /^\s+\S/
196
+ last_line = line_id
197
+ elsif line_id - last_line < 2 and line =~ /^\S/
198
+ last_line = line_id
199
+ end
200
+ if line_id - last_line > 1 or line_id == lines.length - 1
201
+ depth.delete_if do |v|
202
+ lines[last_line] << "" # "\n\t\\end{#{ lT( v ) }}"
203
+ end
204
+ end
205
+ end
206
+ lines.join( "\n" )
207
+ end
208
+ end
209
+
210
+ class RedClothForTex < String
211
+
212
+ VERSION = '2.0.7'
213
+
214
+ #
215
+ # Mapping of 8-bit ASCII codes to HTML numerical entity equivalents.
216
+ # (from PyTextile)
217
+ #
218
+ TEXTILE_TAGS =
219
+
220
+ [[128, 8364], [129, 0], [130, 8218], [131, 402], [132, 8222], [133, 8230],
221
+ [134, 8224], [135, 8225], [136, 710], [137, 8240], [138, 352], [139, 8249],
222
+ [140, 338], [141, 0], [142, 0], [143, 0], [144, 0], [145, 8216], [146, 8217],
223
+ [147, 8220], [148, 8221], [149, 8226], [150, 8211], [151, 8212], [152, 732],
224
+ [153, 8482], [154, 353], [155, 8250], [156, 339], [157, 0], [158, 0], [159, 376]].
225
+
226
+ collect! do |a, b|
227
+ [a.chr, ( b.zero? and "" or "&#{ b };" )]
228
+ end
229
+
230
+ #
231
+ # Regular expressions to convert to HTML.
232
+ #
233
+ A_HLGN = /(?:(?:<>|<|>|\=|[()]+)+)/
234
+ A_VLGN = /[\-^~]/
235
+ C_CLAS = '(?:\([^)]+\))'
236
+ C_LNGE = '(?:\[[^\]]+\])'
237
+ C_STYL = '(?:\{[^}]+\})'
238
+ S_CSPN = '(?:\\\\\d+)'
239
+ S_RSPN = '(?:/\d+)'
240
+ A = "(?:#{A_HLGN}?#{A_VLGN}?|#{A_VLGN}?#{A_HLGN}?)"
241
+ S = "(?:#{S_CSPN}?#{S_RSPN}|#{S_RSPN}?#{S_CSPN}?)"
242
+ C = "(?:#{C_CLAS}?#{C_STYL}?#{C_LNGE}?|#{C_STYL}?#{C_LNGE}?#{C_CLAS}?|#{C_LNGE}?#{C_STYL}?#{C_CLAS}?)"
243
+ # PUNCT = Regexp::quote( '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' )
244
+ PUNCT = Regexp::quote( '!"#$%&\'*+,-./:;=?@\\^_`|~' )
245
+ HYPERLINK = '(\S+?)([^\w\s/;=\?]*?)(\s|$)'
246
+
247
+ GLYPHS = [
248
+ # [ /([^\s\[{(>])?\'([dmst]\b|ll\b|ve\b|\s|:|$)/, '\1&#8217;\2' ], # single closing
249
+ [ /([^\s\[{(>])\'/, '\1&#8217;' ], # single closing
250
+ [ /\'(?=\s|s\b|[#{PUNCT}])/, '&#8217;' ], # single closing
251
+ [ /\'/, '&#8216;' ], # single opening
252
+ # [ /([^\s\[{(])?"(\s|:|$)/, '\1&#8221;\2' ], # double closing
253
+ [ /([^\s\[{(>])"/, '\1&#8221;' ], # double closing
254
+ [ /"(?=\s|[#{PUNCT}])/, '&#8221;' ], # double closing
255
+ [ /"/, '&#8220;' ], # double opening
256
+ [ /\b( )?\.{3}/, '\1&#8230;' ], # ellipsis
257
+ [ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '<acronym title="\2">\1</acronym>' ], # 3+ uppercase acronym
258
+ [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]{2,})([^<a-z0-9]|$)/, '\1<span class="caps">\2</span>\3' ], # 3+ uppercase caps
259
+ [ /(\.\s)?\s?--\s?/, '\1&#8212;' ], # em dash
260
+ [ /\s->\s/, ' &rarr; ' ], # en dash
261
+ [ /\s-\s/, ' &#8211; ' ], # en dash
262
+ [ /(\d+) ?x ?(\d+)/, '\1&#215;\2' ], # dimension sign
263
+ [ /\b ?[(\[]TM[\])]/i, '&#8482;' ], # trademark
264
+ [ /\b ?[(\[]R[\])]/i, '&#174;' ], # registered
265
+ [ /\b ?[(\[]C[\])]/i, '&#169;' ] # copyright
266
+ ]
267
+
268
+ I_ALGN_VALS = {
269
+ '<' => 'left',
270
+ '=' => 'center',
271
+ '>' => 'right'
272
+ }
273
+
274
+ H_ALGN_VALS = {
275
+ '<' => 'left',
276
+ '=' => 'center',
277
+ '>' => 'right',
278
+ '<>' => 'justify'
279
+ }
280
+
281
+ V_ALGN_VALS = {
282
+ '^' => 'top',
283
+ '-' => 'middle',
284
+ '~' => 'bottom'
285
+ }
286
+
287
+ QTAGS = [
288
+ ['**', 'bf'],
289
+ ['*', 'bf'],
290
+ ['??', 'cite'],
291
+ ['-', 'del'],
292
+ ['__', 'underline'],
293
+ ['_', 'em'],
294
+ ['%', 'span'],
295
+ ['+', 'ins'],
296
+ ['^', 'sup'],
297
+ ['~', 'sub']
298
+ ]
299
+
300
+ #
301
+ # Two accessor for setting security restrictions.
302
+ #
303
+ # This is a nice thing if you're using RedCloth for
304
+ # formatting in public places (e.g. Wikis) where you
305
+ # don't want users to abuse HTML for bad things.
306
+ #
307
+ # If +:filter_html+ is set, HTML which wasn't
308
+ # created by the Textile processor will be escaped.
309
+ #
310
+ # If +:filter_styles+ is set, it will also disable
311
+ # the style markup specifier. ('{color: red}')
312
+ #
313
+ attr_accessor :filter_html, :filter_styles
314
+
315
+ #
316
+ # Accessor for toggling line folding.
317
+ #
318
+ # If +:fold_lines+ is set, single newlines will
319
+ # not be converted to break tags.
320
+ #
321
+ attr_accessor :fold_lines
322
+
323
+ def initialize( string, restrictions = [] )
324
+ restrictions.each { |r| method( "#{ r }=" ).call( true ) }
325
+ super( string )
326
+ end
327
+
328
+ #
329
+ # Generate tex.
330
+ #
331
+ def to_tex( lite = false )
332
+
333
+ # make our working copy
334
+ text = self.dup
335
+
336
+ @urlrefs = {}
337
+ @shelf = []
338
+
339
+ # incoming_entities text
340
+ fix_entities text
341
+ clean_white_space text
342
+
343
+ get_refs text
344
+
345
+ no_textile text
346
+
347
+ unless lite
348
+ lists text
349
+ table text
350
+ end
351
+
352
+ glyphs text
353
+
354
+ unless lite
355
+ fold text
356
+ block text
357
+ end
358
+
359
+ retrieve text
360
+ encode_entities text
361
+
362
+ text.gsub!(/\[\[(.*?)\]\]/, "\\1")
363
+ text.gsub!(/_/, "\\_")
364
+ text.gsub!( /<\/?notextile>/, '' )
365
+ # text.gsub!( /x%x%/, '&#38;' )
366
+ # text.gsub!( /<br \/>/, "<br />\n" )
367
+ text.strip!
368
+ text
369
+
370
+ end
371
+
372
+ def pgl( text )
373
+ GLYPHS.each do |re, resub|
374
+ text.gsub! re, resub
375
+ end
376
+ end
377
+
378
+ def pba( text_in, element = "" )
379
+
380
+ return '' unless text_in
381
+
382
+ style = []
383
+ text = text_in.dup
384
+ if element == 'td'
385
+ colspan = $1 if text =~ /\\(\d+)/
386
+ rowspan = $1 if text =~ /\/(\d+)/
387
+ style << "vertical-align:#{ v_align( $& ) };" if text =~ A_VLGN
388
+ end
389
+
390
+ style << "#{ $1 };" if not @filter_styles and
391
+ text.sub!( /\{([^}]*)\}/, '' )
392
+
393
+ lang = $1 if
394
+ text.sub!( /\[([^)]+?)\]/, '' )
395
+
396
+ cls = $1 if
397
+ text.sub!( /\(([^()]+?)\)/, '' )
398
+
399
+ style << "padding-left:#{ $1.length }em;" if
400
+ text.sub!( /([(]+)/, '' )
401
+
402
+ style << "padding-right:#{ $1.length }em;" if text.sub!( /([)]+)/, '' )
403
+
404
+ style << "text-align:#{ h_align( $& ) };" if text =~ A_HLGN
405
+
406
+ cls, id = $1, $2 if cls =~ /^(.*?)#(.*)$/
407
+
408
+ atts = ''
409
+ atts << " style=\"#{ style.join }\"" unless style.empty?
410
+ atts << " class=\"#{ cls }\"" unless cls.to_s.empty?
411
+ atts << " lang=\"#{ lang }\"" if lang
412
+ atts << " id=\"#{ id }\"" if id
413
+ atts << " colspan=\"#{ colspan }\"" if colspan
414
+ atts << " rowspan=\"#{ rowspan }\"" if rowspan
415
+
416
+ atts
417
+ end
418
+
419
+ def table( text )
420
+ text << "\n\n"
421
+ text.gsub!( /^(?:table(_?#{S}#{A}#{C})\. ?\n)?^(#{A}#{C}\.? ?\|.*?\|)\n\n/m ) do |matches|
422
+
423
+ tatts, fullrow = $~[1..2]
424
+ tatts = pba( tatts, 'table' )
425
+ rows = []
426
+
427
+ fullrow.
428
+ split( /\|$/m ).
429
+ delete_if { |x| x.empty? }.
430
+ each do |row|
431
+
432
+ ratts, row = pba( $1, 'tr' ), $2 if row =~ /^(#{A}#{C}\. )(.*)/m
433
+
434
+ cells = []
435
+ row.split( '|' ).each do |cell|
436
+ ctyp = 'd'
437
+ ctyp = 'h' if cell =~ /^_/
438
+
439
+ catts = ''
440
+ catts, cell = pba( $1, 'td' ), $2 if cell =~ /^(_?#{S}#{A}#{C}\. )(.*)/
441
+
442
+ unless cell.strip.empty?
443
+ cells << "\t\t\t<t#{ ctyp }#{ catts }>#{ cell }</t#{ ctyp }>"
444
+ end
445
+ end
446
+ rows << "\t\t<tr#{ ratts }>\n#{ cells.join( "\n" ) }\n\t\t</tr>"
447
+ end
448
+ "\t<table#{ tatts }>\n#{ rows.join( "\n" ) }\n\t</table>\n\n"
449
+ end
450
+ end
451
+
452
+ def lists( text )
453
+ text.gsub!( /^([#*]+?#{C} .*?)$(?![^#*])/m ) do |match|
454
+ lines = match.split( /\n/ )
455
+ last_line = -1
456
+ depth = []
457
+ lines.each_with_index do |line, line_id|
458
+ if line =~ /^([#*]+)(#{A}#{C}) (.*)$/m
459
+ tl,atts,content = $~[1..3]
460
+ if depth.last
461
+ if depth.last.length > tl.length
462
+ (depth.length - 1).downto(0) do |i|
463
+ break if depth[i].length == tl.length
464
+ lines[line_id - 1] << "\n\t\\end{#{ lT( depth[i] ) }}\n\t"
465
+ depth.pop
466
+ end
467
+ end
468
+ if !depth.last.nil? && !tl.length.nil? && depth.last.length == tl.length
469
+ lines[line_id - 1] << ''
470
+ end
471
+ end
472
+ unless depth.last == tl
473
+ depth << tl
474
+ atts = pba( atts )
475
+ lines[line_id] = "\t\\begin{#{ lT(tl) }}\n\t\\item #{ content }"
476
+ else
477
+ lines[line_id] = "\t\t\\item #{ content }"
478
+ end
479
+ last_line = line_id
480
+
481
+ elsif line =~ /^\s+\S/
482
+ last_line = line_id
483
+ elsif line_id - last_line < 2 and line =~ /^\S/
484
+ last_line = line_id
485
+ end
486
+ if line_id - last_line > 1 or line_id == lines.length - 1
487
+ depth.delete_if do |v|
488
+ lines[last_line] << "\n\t\\end{#{ lT( v ) }}"
489
+ end
490
+ end
491
+ end
492
+ lines.join( "\n" )
493
+ end
494
+ end
495
+
496
+ def lT( text )
497
+ text =~ /\#$/ ? 'enumerate' : 'itemize'
498
+ end
499
+
500
+ def fold( text )
501
+ text.gsub!( /(.+)\n(?![#*\s|])/, "\\1\\\\\\\\" )
502
+ # text.gsub!( /(.+)\n(?![#*\s|])/, "\\1#{ @fold_lines ? ' ' : '<br />' }" )
503
+ end
504
+
505
+ def block( text )
506
+ pre = false
507
+ find = ['bq','h[1-6]','fn\d+']
508
+
509
+ regexp_cue = []
510
+
511
+ lines = text.split( /\n/ ) + [' ']
512
+ new_text =
513
+ lines.collect do |line|
514
+ pre = true if line =~ /<(pre|notextile)>/i
515
+ find.each do |tag|
516
+ line.gsub!( /^(#{ tag })(#{A}#{C})\.(?::(\S+))? (.*)$/ ) do |m|
517
+ tag,atts,cite,content = $~[1..4]
518
+
519
+ atts = pba( atts )
520
+
521
+ if tag =~ /fn(\d+)/
522
+ # tag = 'p';
523
+ # atts << " id=\"fn#{ $1 }\""
524
+ regexp_cue << [ /footnote\{#{$1}}/, "footnote{#{content}}" ]
525
+ content = ""
526
+ end
527
+
528
+ if tag =~ /h([1-6])/
529
+ section_type = "sub" * [$1.to_i - 1, 2].min
530
+ start = "\t\\#{section_type}section*{"
531
+ tend = "}"
532
+ end
533
+
534
+ if tag == "bq"
535
+ cite = check_refs( cite )
536
+ cite = " cite=\"#{ cite }\"" if cite
537
+ start = "\t\\begin{quotation}\n\\noindent {\\em ";
538
+ tend = "}\n\t\\end{quotation}";
539
+ end
540
+
541
+ "#{ start }#{ content }#{ tend }"
542
+ end unless pre
543
+ end
544
+
545
+ #line.gsub!( /^(?!\t|<\/?pre|<\/?notextile|<\/?code|$| )(.*)/, "\t<p>\\1</p>" )
546
+
547
+ #line.gsub!( "<br />", "\n" ) if pre
548
+ # pre = false if line =~ /<\/(pre|notextile)>/i
549
+
550
+ line
551
+ end.join( "\n" )
552
+ text.replace( new_text )
553
+ regexp_cue.each { |pair| text.gsub!(pair.first, pair.last) }
554
+ end
555
+
556
+ def span( text )
557
+ QTAGS.each do |tt, ht|
558
+ ttr = Regexp::quote( tt )
559
+ text.gsub!(
560
+
561
+ /(^|\s|\>|[#{PUNCT}{(\[])
562
+ #{ttr}
563
+ (#{C})
564
+ (?::(\S+?))?
565
+ ([^\s#{ttr}]+?(?:[^\n]|\n(?!\n))*?)
566
+ ([#{PUNCT}]*?)
567
+ #{ttr}
568
+ (?=[\])}]|[#{PUNCT}]+?|<|\s|$)/xm
569
+
570
+ ) do |m|
571
+
572
+ start,atts,cite,content,tend = $~[1..5]
573
+ atts = pba( atts )
574
+ atts << " cite=\"#{ cite }\"" if cite
575
+
576
+ "#{ start }{\\#{ ht } #{ content }#{ tend }}"
577
+
578
+ end
579
+ end
580
+ end
581
+
582
+ def links( text )
583
+ text.gsub!( /
584
+ ([\s\[{(]|[#{PUNCT}])? # $pre
585
+ " # start
586
+ (#{C}) # $atts
587
+ ([^"]+?) # $text
588
+ \s?
589
+ (?:\(([^)]+?)\)(?="))? # $title
590
+ ":
591
+ (\S+?) # $url
592
+ (\/)? # $slash
593
+ ([^\w\/;]*?) # $post
594
+ (?=\s|$)
595
+ /x ) do |m|
596
+ pre,atts,text,title,url,slash,post = $~[1..7]
597
+
598
+ url = check_refs( url )
599
+
600
+ atts = pba( atts )
601
+ atts << " title=\"#{ title }\"" if title
602
+ atts = shelve( atts ) if atts
603
+
604
+ "#{ pre }<a href=\"#{ url }#{ slash }\"#{ atts }>#{ text }</a>#{ post }"
605
+ end
606
+ end
607
+
608
+ def get_refs( text )
609
+ text.gsub!( /(^|\s)\[(.+?)\]((?:http:\/\/|javascript:|ftp:\/\/|\/)\S+?)(?=\s|$)/ ) do |m|
610
+ flag, url = $~[1..2]
611
+ @urlrefs[flag] = url
612
+ end
613
+ end
614
+
615
+ def check_refs( text )
616
+ @urlrefs[text] || text
617
+ end
618
+
619
+ def image( text )
620
+ text.gsub!( /
621
+ \! # opening
622
+ (\<|\=|\>)? # optional alignment atts
623
+ (#{C}) # optional style,class atts
624
+ (?:\. )? # optional dot-space
625
+ ([^\s(!]+?) # presume this is the src
626
+ \s? # optional space
627
+ (?:\(((?:[^\(\)]|\([^\)]+\))+?)\))? # optional title
628
+ \! # closing
629
+ (?::#{ HYPERLINK })? # optional href
630
+ /x ) do |m|
631
+ algn,atts,url,title,href,href_a1,href_a2 = $~[1..7]
632
+ atts = pba( atts )
633
+ atts << " align=\"#{ i_align( algn ) }\"" if algn
634
+ atts << " title=\"#{ title }\"" if title
635
+ atts << " alt=\"#{ title }\""
636
+ # size = @getimagesize($url);
637
+ # if($size) $atts.= " $size[3]";
638
+
639
+ href = check_refs( href ) if href
640
+ url = check_refs( url )
641
+
642
+ out = ''
643
+ out << "<a href=\"#{ href }\">" if href
644
+ out << "<img src=\"#{ url }\"#{ atts } />"
645
+ out << "</a>#{ href_a1 }#{ href_a2 }" if href
646
+
647
+ out
648
+ end
649
+ end
650
+
651
+ def code( text )
652
+ text.gsub!( /
653
+ (?:^|([\s\(\[{])) # 1 open bracket?
654
+ @ # opening
655
+ (?:\|(\w+?)\|)? # 2 language
656
+ (\S(?:[^\n]|\n(?!\n))*?) # 3 code
657
+ @ # closing
658
+ (?:$|([\]})])|
659
+ (?=[#{PUNCT}]{1,2}|
660
+ \s)) # 4 closing bracket?
661
+ /x ) do |m|
662
+ before,lang,code,after = $~[1..4]
663
+ lang = " language=\"#{ lang }\"" if lang
664
+ "#{ before }<code#{ lang }>#{ code }</code>#{ after }"
665
+ end
666
+ end
667
+
668
+ def shelve( val )
669
+ @shelf << val
670
+ " <#{ @shelf.length }>"
671
+ end
672
+
673
+ def retrieve( text )
674
+ @shelf.each_with_index do |r, i|
675
+ text.gsub!( " <#{ i + 1 }>", r )
676
+ end
677
+ end
678
+
679
+ def incoming_entities( text )
680
+ ## turn any incoming ampersands into a dummy character for now.
681
+ ## This uses a negative lookahead for alphanumerics followed by a semicolon,
682
+ ## implying an incoming html entity, to be skipped
683
+
684
+ text.gsub!( /&(?![#a-z0-9]+;)/i, "x%x%" )
685
+ end
686
+
687
+ def encode_entities( text )
688
+ ## Convert high and low ascii to entities.
689
+ # if $-K == "UTF-8"
690
+ # encode_high( text )
691
+ # else
692
+ text.texesc!( :NoQuotes )
693
+ # end
694
+ end
695
+
696
+ def fix_entities( text )
697
+ ## de-entify any remaining angle brackets or ampersands
698
+ text.gsub!( "\&", "&" )
699
+ text.gsub!( "\%", "%" )
700
+ end
701
+
702
+ def clean_white_space( text )
703
+ text.gsub!( /\r\n/, "\n" )
704
+ text.gsub!( /\t/, '' )
705
+ text.gsub!( /\n{3,}/, "\n\n" )
706
+ text.gsub!( /\n *\n/, "\n\n" )
707
+ text.gsub!( /"$/, "\" " )
708
+ end
709
+
710
+ def no_textile( text )
711
+ text.gsub!( /(^|\s)==(.*?)==(\s|$)?/,
712
+ '\1<notextile>\2</notextile>\3' )
713
+ end
714
+
715
+ def footnote_ref( text )
716
+ text.gsub!( /\[([0-9]+?)\](\s)?/,
717
+ '\footnote{\1}\2')
718
+ #'<sup><a href="#fn\1">\1</a></sup>\2' )
719
+ end
720
+
721
+ def inline( text )
722
+ image text
723
+ links text
724
+ code text
725
+ span text
726
+ end
727
+
728
+ def glyphs_deep( text )
729
+ codepre = 0
730
+ offtags = /(?:code|pre|kbd|notextile)/
731
+ if text !~ /<.*>/
732
+ # pgl text
733
+ footnote_ref text
734
+ else
735
+ used_offtags = {}
736
+ text.gsub!( /(?:[^<].*?(?=<[^\n]*?>|$)|<[^\n]*?>+)/m ) do |line|
737
+ tagline = ( line =~ /^<.*>/ )
738
+
739
+ ## matches are off if we're between <code>, <pre> etc.
740
+ if tagline
741
+ if line =~ /<(#{ offtags })>/i
742
+ codepre += 1
743
+ used_offtags[$1] = true
744
+ line.texesc!( :NoQuotes ) if codepre - used_offtags.length > 0
745
+ elsif line =~ /<\/(#{ offtags })>/i
746
+ line.texesc!( :NoQuotes ) if codepre - used_offtags.length > 0
747
+ codepre -= 1 unless codepre.zero?
748
+ used_offtags = {} if codepre.zero?
749
+ elsif @filter_html or codepre > 0
750
+ line.texesc!( :NoQuotes )
751
+ ## line.gsub!( /&lt;(\/?#{ offtags })&gt;/, '<\1>' )
752
+ end
753
+ ## do htmlspecial if between <code>
754
+ elsif codepre > 0
755
+ line.texesc!( :NoQuotes )
756
+ ## line.gsub!( /&lt;(\/?#{ offtags })&gt;/, '<\1>' )
757
+ elsif not tagline
758
+ inline line
759
+ glyphs_deep line
760
+ end
761
+
762
+ line
763
+ end
764
+ end
765
+ end
766
+
767
+ def glyphs( text )
768
+ text.gsub!( /"\z/, "\" " )
769
+ ## if no html, do a simple search and replace...
770
+ if text !~ /<.*>/
771
+ inline text
772
+ end
773
+ glyphs_deep text
774
+ end
775
+
776
+ def i_align( text )
777
+ I_ALGN_VALS[text]
778
+ end
779
+
780
+ def h_align( text )
781
+ H_ALGN_VALS[text]
782
+ end
783
+
784
+ def v_align( text )
785
+ V_ALGN_VALS[text]
786
+ end
787
+
788
+ def encode_high( text )
789
+ ## mb_encode_numericentity($text, $cmap, $charset);
790
+ end
791
+
792
+ def decode_high( text )
793
+ ## mb_decode_numericentity($text, $cmap, $charset);
794
+ end
795
+
796
+ def textile_popup_help( name, helpvar, windowW, windowH )
797
+ ' <a target="_blank" href="http://www.textpattern.com/help/?item=' + helpvar + '" onclick="window.open(this.href, \'popupwindow\', \'width=' + windowW + ',height=' + windowH + ',scrollbars,resizable\'); return false;">' + name + '</a><br />'
798
+ end
799
+
800
+ CMAP = [
801
+ 160, 255, 0, 0xffff,
802
+ 402, 402, 0, 0xffff,
803
+ 913, 929, 0, 0xffff,
804
+ 931, 937, 0, 0xffff,
805
+ 945, 969, 0, 0xffff,
806
+ 977, 978, 0, 0xffff,
807
+ 982, 982, 0, 0xffff,
808
+ 8226, 8226, 0, 0xffff,
809
+ 8230, 8230, 0, 0xffff,
810
+ 8242, 8243, 0, 0xffff,
811
+ 8254, 8254, 0, 0xffff,
812
+ 8260, 8260, 0, 0xffff,
813
+ 8465, 8465, 0, 0xffff,
814
+ 8472, 8472, 0, 0xffff,
815
+ 8476, 8476, 0, 0xffff,
816
+ 8482, 8482, 0, 0xffff,
817
+ 8501, 8501, 0, 0xffff,
818
+ 8592, 8596, 0, 0xffff,
819
+ 8629, 8629, 0, 0xffff,
820
+ 8656, 8660, 0, 0xffff,
821
+ 8704, 8704, 0, 0xffff,
822
+ 8706, 8707, 0, 0xffff,
823
+ 8709, 8709, 0, 0xffff,
824
+ 8711, 8713, 0, 0xffff,
825
+ 8715, 8715, 0, 0xffff,
826
+ 8719, 8719, 0, 0xffff,
827
+ 8721, 8722, 0, 0xffff,
828
+ 8727, 8727, 0, 0xffff,
829
+ 8730, 8730, 0, 0xffff,
830
+ 8733, 8734, 0, 0xffff,
831
+ 8736, 8736, 0, 0xffff,
832
+ 8743, 8747, 0, 0xffff,
833
+ 8756, 8756, 0, 0xffff,
834
+ 8764, 8764, 0, 0xffff,
835
+ 8773, 8773, 0, 0xffff,
836
+ 8776, 8776, 0, 0xffff,
837
+ 8800, 8801, 0, 0xffff,
838
+ 8804, 8805, 0, 0xffff,
839
+ 8834, 8836, 0, 0xffff,
840
+ 8838, 8839, 0, 0xffff,
841
+ 8853, 8853, 0, 0xffff,
842
+ 8855, 8855, 0, 0xffff,
843
+ 8869, 8869, 0, 0xffff,
844
+ 8901, 8901, 0, 0xffff,
845
+ 8968, 8971, 0, 0xffff,
846
+ 9001, 9002, 0, 0xffff,
847
+ 9674, 9674, 0, 0xffff,
848
+ 9824, 9824, 0, 0xffff,
849
+ 9827, 9827, 0, 0xffff,
850
+ 9829, 9830, 0, 0xffff,
851
+ 338, 339, 0, 0xffff,
852
+ 352, 353, 0, 0xffff,
853
+ 376, 376, 0, 0xffff,
854
+ 710, 710, 0, 0xffff,
855
+ 732, 732, 0, 0xffff,
856
+ 8194, 8195, 0, 0xffff,
857
+ 8201, 8201, 0, 0xffff,
858
+ 8204, 8207, 0, 0xffff,
859
+ 8211, 8212, 0, 0xffff,
860
+ 8216, 8218, 0, 0xffff,
861
+ 8218, 8218, 0, 0xffff,
862
+ 8220, 8222, 0, 0xffff,
863
+ 8224, 8225, 0, 0xffff,
864
+ 8240, 8240, 0, 0xffff,
865
+ 8249, 8250, 0, 0xffff,
866
+ 8364, 8364, 0, 0xffff
867
+ ]
868
+ end
869
+