textilize 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2012 Mysen Huang
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
data/README.md ADDED
@@ -0,0 +1,44 @@
1
+ Textilize
2
+ =========
3
+
4
+ As of version 3, Rails doesn't have the `textilize` and `textilize_without_paragraph` helper methods.
5
+ Textilize is a gem brings back the missing method for Rails 3, and *it includes the library RedCloth 3.0.4* (newest is at 4.X), which doesn't need to be compiled on server.
6
+
7
+ The reason we need this gem is that we use :textilize at a few places in our apps, and we don't need super fast RedCloth, we just need a working version that don't force us to install C extensions on various production servers.
8
+ This could be useful for bundle-package usage, where you can rely on the bundle/cache gems.
9
+
10
+ BTW, Textilize is not always the top choice, there are some useful gems that are doing it great, but they will requires C extension due to higher version of RedCloth dependency:
11
+
12
+ https://github.com/dtrasbo/formatize/
13
+
14
+ https://github.com/rohit/prarupa
15
+
16
+
17
+ Installation
18
+ ------------
19
+
20
+ Put `gem 'textilize'` into your Gemfile and do a `bundle install`, and that's
21
+ it.
22
+
23
+ Usage
24
+ -----
25
+
26
+ # textilize("I _love_ ROR(Ruby on Rails)!")
27
+ # # => "<p>I <em>love</em> <acronym title="Ruby on Rails">ROR</acronym>!</p>"
28
+
29
+ # textilize_without_paragraph("I _love_ ROR(Ruby on Rails)!")
30
+ # # => "I <em>love</em> <acronym title="Ruby on Rails">ROR</acronym>!"
31
+
32
+
33
+ Test
34
+ ------------
35
+
36
+ We will add some tests back later.
37
+
38
+ Copyright & Licensing
39
+ ---------------------
40
+
41
+ Copyright (c) 2012 Kudelabs
42
+
43
+ Released under the MIT License. See LICENSE for details.
44
+
data/lib/redcloth.rb ADDED
@@ -0,0 +1,1137 @@
1
+ #this version of RedCloth doenn't need to be compile as C extension, and I love it.
2
+ #Newer version ~> 4.X needs compiling C.
3
+ # vim:ts=4:sw=4:
4
+ # = RedCloth - Textile and Markdown Hybrid for Ruby
5
+ #
6
+ # Homepage:: http://whytheluckystiff.net/ruby/redcloth/
7
+ # Author:: why the lucky stiff (http://whytheluckystiff.net/)
8
+ # Copyright:: (cc) 2004 why the lucky stiff (and his puppet organizations.)
9
+ # License:: BSD
10
+ #
11
+ # (see http://hobix.com/textile/ for a Textile Reference.)
12
+ #
13
+ # Based on (and also inspired by) both:
14
+ #
15
+ # PyTextile: http://diveintomark.org/projects/textile/textile.py.txt
16
+ # Textism for PHP: http://www.textism.com/tools/textile/
17
+ #
18
+ #
19
+
20
+ # = RedCloth
21
+ #
22
+ # RedCloth is a Ruby library for converting Textile and/or Markdown
23
+ # into HTML. You can use either format, intermingled or separately.
24
+ # You can also extend RedCloth to honor your own custom text stylings.
25
+ #
26
+ # RedCloth users are encouraged to use Textile if they are generating
27
+ # HTML and to use Markdown if others will be viewing the plain text.
28
+ #
29
+ # == What is Textile?
30
+ #
31
+ # Textile is a simple formatting style for text
32
+ # documents, loosely based on some HTML conventions.
33
+ #
34
+ # == Sample Textile Text
35
+ #
36
+ # h2. This is a title
37
+ #
38
+ # h3. This is a subhead
39
+ #
40
+ # This is a bit of paragraph.
41
+ #
42
+ # bq. This is a blockquote.
43
+ #
44
+ # = Writing Textile
45
+ #
46
+ # A Textile document consists of paragraphs. Paragraphs
47
+ # can be specially formatted by adding a small instruction
48
+ # to the beginning of the paragraph.
49
+ #
50
+ # h[n]. Header of size [n].
51
+ # bq. Blockquote.
52
+ # # Numeric list.
53
+ # * Bulleted list.
54
+ #
55
+ # == Quick Phrase Modifiers
56
+ #
57
+ # Quick phrase modifiers are also included, to allow formatting
58
+ # of small portions of text within a paragraph.
59
+ #
60
+ # \_emphasis\_
61
+ # \_\_italicized\_\_
62
+ # \*strong\*
63
+ # \*\*bold\*\*
64
+ # ??citation??
65
+ # -deleted text-
66
+ # +inserted text+
67
+ # ^superscript^
68
+ # ~subscript~
69
+ # @code@
70
+ # %(classname)span%
71
+ #
72
+ # ==notextile== (leave text alone)
73
+ #
74
+ # == Links
75
+ #
76
+ # To make a hypertext link, put the link text in "quotation
77
+ # marks" followed immediately by a colon and the URL of the link.
78
+ #
79
+ # Optional: text in (parentheses) following the link text,
80
+ # but before the closing quotation mark, will become a Title
81
+ # attribute for the link, visible as a tool tip when a cursor is above it.
82
+ #
83
+ # Example:
84
+ #
85
+ # "This is a link (This is a title) ":http://www.textism.com
86
+ #
87
+ # Will become:
88
+ #
89
+ # <a href="http://www.textism.com" title="This is a title">This is a link</a>
90
+ #
91
+ # == Images
92
+ #
93
+ # To insert an image, put the URL for the image inside exclamation marks.
94
+ #
95
+ # Optional: text that immediately follows the URL in (parentheses) will
96
+ # be used as the Alt text for the image. Images on the web should always
97
+ # have descriptive Alt text for the benefit of readers using non-graphical
98
+ # browsers.
99
+ #
100
+ # Optional: place a colon followed by a URL immediately after the
101
+ # closing ! to make the image into a link.
102
+ #
103
+ # Example:
104
+ #
105
+ # !http://www.textism.com/common/textist.gif(Textist)!
106
+ #
107
+ # Will become:
108
+ #
109
+ # <img src="http://www.textism.com/common/textist.gif" alt="Textist" />
110
+ #
111
+ # With a link:
112
+ #
113
+ # !/common/textist.gif(Textist)!:http://textism.com
114
+ #
115
+ # Will become:
116
+ #
117
+ # <a href="http://textism.com"><img src="/common/textist.gif" alt="Textist" /></a>
118
+ #
119
+ # == Defining Acronyms
120
+ #
121
+ # HTML allows authors to define acronyms via the tag. The definition appears as a
122
+ # tool tip when a cursor hovers over the acronym. A crucial aid to clear writing,
123
+ # this should be used at least once for each acronym in documents where they appear.
124
+ #
125
+ # To quickly define an acronym in Textile, place the full text in (parentheses)
126
+ # immediately following the acronym.
127
+ #
128
+ # Example:
129
+ #
130
+ # ACLU(American Civil Liberties Union)
131
+ #
132
+ # Will become:
133
+ #
134
+ # <acronym title="American Civil Liberties Union">ACLU</acronym>
135
+ #
136
+ # == Adding Tables
137
+ #
138
+ # In Textile, simple tables can be added by seperating each column by
139
+ # a pipe.
140
+ #
141
+ # |a|simple|table|row|
142
+ # |And|Another|table|row|
143
+ #
144
+ # Attributes are defined by style definitions in parentheses.
145
+ #
146
+ # table(border:1px solid black).
147
+ # (background:#ddd;color:red). |{}| | | |
148
+ #
149
+ # == Using RedCloth
150
+ #
151
+ # RedCloth is simply an extension of the String class, which can handle
152
+ # Textile formatting. Use it like a String and output HTML with its
153
+ # RedCloth#to_html method.
154
+ #
155
+ # doc = RedCloth.new "
156
+ #
157
+ # h2. Test document
158
+ #
159
+ # Just a simple test."
160
+ #
161
+ # puts doc.to_html
162
+ #
163
+ # By default, RedCloth uses both Textile and Markdown formatting, with
164
+ # Textile formatting taking precedence. If you want to turn off Markdown
165
+ # formatting, to boost speed and limit the processor:
166
+ #
167
+ # class RedCloth::Textile.new( str )
168
+
169
+ class RedCloth < String
170
+
171
+ VERSION = '3.0.4'
172
+ DEFAULT_RULES = [:textile, :markdown]
173
+
174
+ #
175
+ # Two accessor for setting security restrictions.
176
+ #
177
+ # This is a nice thing if you're using RedCloth for
178
+ # formatting in public places (e.g. Wikis) where you
179
+ # don't want users to abuse HTML for bad things.
180
+ #
181
+ # If +:filter_html+ is set, HTML which wasn't
182
+ # created by the Textile processor will be escaped.
183
+ #
184
+ # If +:filter_styles+ is set, it will also disable
185
+ # the style markup specifier. ('{color: red}')
186
+ #
187
+ attr_accessor :filter_html, :filter_styles
188
+
189
+ #
190
+ # Accessor for toggling hard breaks.
191
+ #
192
+ # If +:hard_breaks+ is set, single newlines will
193
+ # be converted to HTML break tags. This is the
194
+ # default behavior for traditional RedCloth.
195
+ #
196
+ attr_accessor :hard_breaks
197
+
198
+ # Accessor for toggling lite mode.
199
+ #
200
+ # In lite mode, block-level rules are ignored. This means
201
+ # that tables, paragraphs, lists, and such aren't available.
202
+ # Only the inline markup for bold, italics, entities and so on.
203
+ #
204
+ # r = RedCloth.new( "And then? She *fell*!", [:lite_mode] )
205
+ # r.to_html
206
+ # #=> "And then? She <strong>fell</strong>!"
207
+ #
208
+ attr_accessor :lite_mode
209
+
210
+ #
211
+ # Accessor for toggling span caps.
212
+ #
213
+ # Textile places `span' tags around capitalized
214
+ # words by default, but this wreaks havoc on Wikis.
215
+ # If +:no_span_caps+ is set, this will be
216
+ # suppressed.
217
+ #
218
+ attr_accessor :no_span_caps
219
+
220
+ #
221
+ # Establishes the markup predence. Available rules include:
222
+ #
223
+ # == Textile Rules
224
+ #
225
+ # The following textile rules can be set individually. Or add the complete
226
+ # set of rules with the single :textile rule, which supplies the rule set in
227
+ # the following precedence:
228
+ #
229
+ # refs_textile:: Textile references (i.e. [hobix]http://hobix.com/)
230
+ # block_textile_table:: Textile table block structures
231
+ # block_textile_lists:: Textile list structures
232
+ # block_textile_prefix:: Textile blocks with prefixes (i.e. bq., h2., etc.)
233
+ # inline_textile_image:: Textile inline images
234
+ # inline_textile_link:: Textile inline links
235
+ # inline_textile_span:: Textile inline spans
236
+ # glyphs_textile:: Textile entities (such as em-dashes and smart quotes)
237
+ #
238
+ # == Markdown
239
+ #
240
+ # refs_markdown:: Markdown references (for example: [hobix]: http://hobix.com/)
241
+ # block_markdown_setext:: Markdown setext headers
242
+ # block_markdown_atx:: Markdown atx headers
243
+ # block_markdown_rule:: Markdown horizontal rules
244
+ # block_markdown_bq:: Markdown blockquotes
245
+ # block_markdown_lists:: Markdown lists
246
+ # inline_markdown_link:: Markdown links
247
+ attr_accessor :rules
248
+
249
+ # Returns a new RedCloth object, based on _string_ and
250
+ # enforcing all the included _restrictions_.
251
+ #
252
+ # r = RedCloth.new( "h1. A <b>bold</b> man", [:filter_html] )
253
+ # r.to_html
254
+ # #=>"<h1>A &lt;b&gt;bold&lt;/b&gt; man</h1>"
255
+ #
256
+ def initialize( string, restrictions = [] )
257
+ restrictions.each { |r| method( "#{ r }=" ).call( true ) }
258
+ super( string )
259
+ end
260
+
261
+ #
262
+ # Generates HTML from the Textile contents.
263
+ #
264
+ # r = RedCloth.new( "And then? She *fell*!" )
265
+ # r.to_html( true )
266
+ # #=>"And then? She <strong>fell</strong>!"
267
+ #
268
+ def to_html( *rules )
269
+ rules = DEFAULT_RULES if rules.empty?
270
+ # make our working copy
271
+ text = self.dup
272
+
273
+ @urlrefs = {}
274
+ @shelf = []
275
+ textile_rules = [:refs_textile, :block_textile_table, :block_textile_lists,
276
+ :block_textile_prefix, :inline_textile_image, :inline_textile_link,
277
+ :inline_textile_code, :inline_textile_span, :glyphs_textile]
278
+ markdown_rules = [:refs_markdown, :block_markdown_setext, :block_markdown_atx, :block_markdown_rule,
279
+ :block_markdown_bq, :block_markdown_lists,
280
+ :inline_markdown_reflink, :inline_markdown_link]
281
+ @rules = rules.collect do |rule|
282
+ case rule
283
+ when :markdown
284
+ markdown_rules
285
+ when :textile
286
+ textile_rules
287
+ else
288
+ rule
289
+ end
290
+ end.flatten
291
+
292
+ # standard clean up
293
+ incoming_entities text
294
+ clean_white_space text
295
+
296
+ # start processor
297
+ @pre_list = []
298
+ rip_offtags text
299
+ no_textile text
300
+ hard_break text
301
+ unless @lite_mode
302
+ refs text
303
+ blocks text
304
+ end
305
+ inline text
306
+ smooth_offtags text
307
+
308
+ retrieve text
309
+
310
+ text.gsub!( /<\/?notextile>/, '' )
311
+ text.gsub!( /x%x%/, '&#38;' )
312
+ clean_html text if filter_html
313
+ text.strip!
314
+ text
315
+
316
+ end
317
+
318
+ #######
319
+ private
320
+ #######
321
+ #
322
+ # Mapping of 8-bit ASCII codes to HTML numerical entity equivalents.
323
+ # (from PyTextile)
324
+ #
325
+ TEXTILE_TAGS =
326
+
327
+ [[128, 8364], [129, 0], [130, 8218], [131, 402], [132, 8222], [133, 8230],
328
+ [134, 8224], [135, 8225], [136, 710], [137, 8240], [138, 352], [139, 8249],
329
+ [140, 338], [141, 0], [142, 0], [143, 0], [144, 0], [145, 8216], [146, 8217],
330
+ [147, 8220], [148, 8221], [149, 8226], [150, 8211], [151, 8212], [152, 732],
331
+ [153, 8482], [154, 353], [155, 8250], [156, 339], [157, 0], [158, 0], [159, 376]].
332
+
333
+ collect! do |a, b|
334
+ [a.chr, ( b.zero? and "" or "&#{ b };" )]
335
+ end
336
+
337
+ #
338
+ # Regular expressions to convert to HTML.
339
+ #
340
+ A_HLGN = /(?:(?:<>|<|>|\=|[()]+)+)/
341
+ A_VLGN = /[\-^~]/
342
+ C_CLAS = '(?:\([^)]+\))'
343
+ C_LNGE = '(?:\[[^\]]+\])'
344
+ C_STYL = '(?:\{[^}]+\})'
345
+ S_CSPN = '(?:\\\\\d+)'
346
+ S_RSPN = '(?:/\d+)'
347
+ A = "(?:#{A_HLGN}?#{A_VLGN}?|#{A_VLGN}?#{A_HLGN}?)"
348
+ S = "(?:#{S_CSPN}?#{S_RSPN}|#{S_RSPN}?#{S_CSPN}?)"
349
+ C = "(?:#{C_CLAS}?#{C_STYL}?#{C_LNGE}?|#{C_STYL}?#{C_LNGE}?#{C_CLAS}?|#{C_LNGE}?#{C_STYL}?#{C_CLAS}?)"
350
+ # PUNCT = Regexp::quote( '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' )
351
+ PUNCT = Regexp::quote( '!"#$%&\'*+,-./:;=?@\\^_`|~' )
352
+ PUNCT_NOQ = Regexp::quote( '!"#$&\',./:;=?@\\`|' )
353
+ PUNCT_Q = Regexp::quote( '*-_+^~%' )
354
+ HYPERLINK = '(\S+?)([^\w\s/;=\?]*?)(?=\s|<|$)'
355
+
356
+ # Text markup tags, don't conflict with block tags
357
+ SIMPLE_HTML_TAGS = [
358
+ 'tt', 'b', 'i', 'big', 'small', 'em', 'strong', 'dfn', 'code',
359
+ 'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'a', 'img', 'br',
360
+ 'br', 'map', 'q', 'sub', 'sup', 'span', 'bdo'
361
+ ]
362
+
363
+ QTAGS = [
364
+ ['**', 'b'],
365
+ ['*', 'strong'],
366
+ ['??', 'cite', :limit],
367
+ ['-', 'del', :limit],
368
+ ['__', 'i'],
369
+ ['_', 'em', :limit],
370
+ ['%', 'span', :limit],
371
+ ['+', 'ins', :limit],
372
+ ['^', 'sup'],
373
+ ['~', 'sub']
374
+ ]
375
+ QTAGS.collect! do |rc, ht, rtype|
376
+ rcq = Regexp::quote rc
377
+ re =
378
+ case rtype
379
+ when :limit
380
+ /(\W)
381
+ (#{rcq})
382
+ (#{C})
383
+ (?::(\S+?))?
384
+ (\S.*?\S|\S)
385
+ #{rcq}
386
+ (?=\W)/x
387
+ else
388
+ /(#{rcq})
389
+ (#{C})
390
+ (?::(\S+))?
391
+ (\S.*?\S|\S)
392
+ #{rcq}/xm
393
+ end
394
+ [rc, ht, re, rtype]
395
+ end
396
+
397
+ # Elements to handle
398
+ GLYPHS = [
399
+ # [ /([^\s\[{(>])?\'([dmst]\b|ll\b|ve\b|\s|:|$)/, '\1&#8217;\2' ], # single closing
400
+ [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)\'/, '\1&#8217;' ], # single closing
401
+ [ /\'(?=[#{PUNCT_Q}]*(s\b|[\s#{PUNCT_NOQ}]))/, '&#8217;' ], # single closing
402
+ [ /\'/, '&#8216;' ], # single opening
403
+ [ /</, '&lt;' ], # less-than
404
+ [ />/, '&gt;' ], # greater-than
405
+ # [ /([^\s\[{(])?"(\s|:|$)/, '\1&#8221;\2' ], # double closing
406
+ [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)"/, '\1&#8221;' ], # double closing
407
+ [ /"(?=[#{PUNCT_Q}]*[\s#{PUNCT_NOQ}])/, '&#8221;' ], # double closing
408
+ [ /"/, '&#8220;' ], # double opening
409
+ [ /\b( )?\.{3}/, '\1&#8230;' ], # ellipsis
410
+ [ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '<acronym title="\2">\1</acronym>' ], # 3+ uppercase acronym
411
+ [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]+[A-Z0-9])([^<A-Za-z0-9]|$)/, '\1<span class="caps">\2</span>\3', :no_span_caps ], # 3+ uppercase caps
412
+ [ /(\.\s)?\s?--\s?/, '\1&#8212;' ], # em dash
413
+ [ /\s->\s/, ' &rarr; ' ], # right arrow
414
+ [ /\s-\s/, ' &#8211; ' ], # en dash
415
+ [ /(\d+) ?x ?(\d+)/, '\1&#215;\2' ], # dimension sign
416
+ [ /\b ?[(\[]TM[\])]/i, '&#8482;' ], # trademark
417
+ [ /\b ?[(\[]R[\])]/i, '&#174;' ], # registered
418
+ [ /\b ?[(\[]C[\])]/i, '&#169;' ] # copyright
419
+ ]
420
+
421
+ H_ALGN_VALS = {
422
+ '<' => 'left',
423
+ '=' => 'center',
424
+ '>' => 'right',
425
+ '<>' => 'justify'
426
+ }
427
+
428
+ V_ALGN_VALS = {
429
+ '^' => 'top',
430
+ '-' => 'middle',
431
+ '~' => 'bottom'
432
+ }
433
+
434
+ #
435
+ # Flexible HTML escaping
436
+ #
437
+ def htmlesc( str, mode )
438
+ str.gsub!( '&', '&amp;' )
439
+ str.gsub!( '"', '&quot;' ) if mode != :NoQuotes
440
+ str.gsub!( "'", '&#039;' ) if mode == :Quotes
441
+ str.gsub!( '<', '&lt;')
442
+ str.gsub!( '>', '&gt;')
443
+ end
444
+
445
+ # Search and replace for Textile glyphs (quotes, dashes, other symbols)
446
+ def pgl( text )
447
+ GLYPHS.each do |re, resub, tog|
448
+ next if tog and method( tog ).call
449
+ text.gsub! re, resub
450
+ end
451
+ end
452
+
453
+ # Parses Textile attribute lists and builds an HTML attribute string
454
+ def pba( text_in, element = "" )
455
+
456
+ return '' unless text_in
457
+
458
+ style = []
459
+ text = text_in.dup
460
+ if element == 'td'
461
+ colspan = $1 if text =~ /\\(\d+)/
462
+ rowspan = $1 if text =~ /\/(\d+)/
463
+ style << "vertical-align:#{ v_align( $& ) };" if text =~ A_VLGN
464
+ end
465
+
466
+ style << "#{ $1 };" if not filter_styles and
467
+ text.sub!( /\{([^}]*)\}/, '' )
468
+
469
+ lang = $1 if
470
+ text.sub!( /\[([^)]+?)\]/, '' )
471
+
472
+ cls = $1 if
473
+ text.sub!( /\(([^()]+?)\)/, '' )
474
+
475
+ style << "padding-left:#{ $1.length }em;" if
476
+ text.sub!( /([(]+)/, '' )
477
+
478
+ style << "padding-right:#{ $1.length }em;" if text.sub!( /([)]+)/, '' )
479
+
480
+ style << "text-align:#{ h_align( $& ) };" if text =~ A_HLGN
481
+
482
+ cls, id = $1, $2 if cls =~ /^(.*?)#(.*)$/
483
+
484
+ atts = ''
485
+ atts << " style=\"#{ style.join }\"" unless style.empty?
486
+ atts << " class=\"#{ cls }\"" unless cls.to_s.empty?
487
+ atts << " lang=\"#{ lang }\"" if lang
488
+ atts << " id=\"#{ id }\"" if id
489
+ atts << " colspan=\"#{ colspan }\"" if colspan
490
+ atts << " rowspan=\"#{ rowspan }\"" if rowspan
491
+
492
+ atts
493
+ end
494
+
495
+ TABLE_RE = /^(?:table(_?#{S}#{A}#{C})\. ?\n)?^(#{A}#{C}\.? ?\|.*?\|)(\n\n|\Z)/m
496
+
497
+ # Parses a Textile table block, building HTML from the result.
498
+ def block_textile_table( text )
499
+ text.gsub!( TABLE_RE ) do |matches|
500
+
501
+ tatts, fullrow = $~[1..2]
502
+ tatts = pba( tatts, 'table' )
503
+ tatts = shelve( tatts ) if tatts
504
+ rows = []
505
+
506
+ fullrow.
507
+ split( /\|$/m ).
508
+ delete_if { |x| x.empty? }.
509
+ each do |row|
510
+
511
+ ratts, row = pba( $1, 'tr' ), $2 if row =~ /^(#{A}#{C}\. )(.*)/m
512
+
513
+ cells = []
514
+ row.split( '|' ).each do |cell|
515
+ ctyp = 'd'
516
+ ctyp = 'h' if cell =~ /^_/
517
+
518
+ catts = ''
519
+ catts, cell = pba( $1, 'td' ), $2 if cell =~ /^(_?#{S}#{A}#{C}\. ?)(.*)/
520
+
521
+ unless cell.strip.empty?
522
+ catts = shelve( catts ) if catts
523
+ cells << "\t\t\t<t#{ ctyp }#{ catts }>#{ cell }</t#{ ctyp }>"
524
+ end
525
+ end
526
+ ratts = shelve( ratts ) if ratts
527
+ rows << "\t\t<tr#{ ratts }>\n#{ cells.join( "\n" ) }\n\t\t</tr>"
528
+ end
529
+ "\t<table#{ tatts }>\n#{ rows.join( "\n" ) }\n\t</table>\n\n"
530
+ end
531
+ end
532
+
533
+ LISTS_RE = /^([#*]+?#{C} .*?)$(?![^#*])/m
534
+ LISTS_CONTENT_RE = /^([#*]+)(#{A}#{C}) (.*)$/m
535
+
536
+ # Parses Textile lists and generates HTML
537
+ def block_textile_lists( text )
538
+ text.gsub!( LISTS_RE ) do |match|
539
+ lines = match.split( /\n/ )
540
+ last_line = -1
541
+ depth = []
542
+ lines.each_with_index do |line, line_id|
543
+ if line =~ LISTS_CONTENT_RE
544
+ tl,atts,content = $~[1..3]
545
+ if depth.last
546
+ if depth.last.length > tl.length
547
+ (depth.length - 1).downto(0) do |i|
548
+ break if depth[i].length == tl.length
549
+ lines[line_id - 1] << "</li>\n\t</#{ lT( depth[i] ) }l>\n\t"
550
+ depth.pop
551
+ end
552
+ end
553
+ if depth.last and depth.last.length == tl.length
554
+ lines[line_id - 1] << '</li>'
555
+ end
556
+ end
557
+ unless depth.last == tl
558
+ depth << tl
559
+ atts = pba( atts )
560
+ atts = shelve( atts ) if atts
561
+ lines[line_id] = "\t<#{ lT(tl) }l#{ atts }>\n\t<li>#{ content }"
562
+ else
563
+ lines[line_id] = "\t\t<li>#{ content }"
564
+ end
565
+ last_line = line_id
566
+
567
+ else
568
+ last_line = line_id
569
+ end
570
+ if line_id - last_line > 1 or line_id == lines.length - 1
571
+ depth.delete_if do |v|
572
+ lines[last_line] << "</li>\n\t</#{ lT( v ) }l>"
573
+ end
574
+ end
575
+ end
576
+ lines.join( "\n" )
577
+ end
578
+ end
579
+
580
+ CODE_RE = /(\W)
581
+ @
582
+ (?:\|(\w+?)\|)?
583
+ (.+?)
584
+ @
585
+ (?=\W)/x
586
+
587
+ def inline_textile_code( text )
588
+ text.gsub!( CODE_RE ) do |m|
589
+ before,lang,code,after = $~[1..4]
590
+ lang = " lang=\"#{ lang }\"" if lang
591
+ rip_offtags( "#{ before }<code#{ lang }>#{ code }</code>#{ after }" )
592
+ end
593
+ end
594
+
595
+ def lT( text )
596
+ text =~ /\#$/ ? 'o' : 'u'
597
+ end
598
+
599
+ # def hard_break( text )
600
+ # text.gsub!( /(.)\n(?!\Z| *([#*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks
601
+ # end
602
+ # Patch for RedCloth. Fixed in RedCloth r128 but _why hasn't released it yet.
603
+ # <a href="http://code.whytheluckystiff.net/redcloth/changeset/128">http://code.whytheluckystiff.net/redcloth/changeset/128</a>
604
+ def hard_break( text )
605
+ text.gsub!( /(.)\n(?!\n|\Z| *([#*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks
606
+ end
607
+
608
+ BLOCKS_GROUP_RE = /\n{2,}(?! )/m
609
+
610
+ def blocks( text, deep_code = false )
611
+ text.replace( text.split( BLOCKS_GROUP_RE ).collect do |blk|
612
+ plain = blk !~ /\A[#*> ]/
613
+
614
+ # skip blocks that are complex HTML
615
+ if blk =~ /^<\/?(\w+).*>/ and not SIMPLE_HTML_TAGS.include? $1
616
+ blk
617
+ else
618
+ # search for indentation levels
619
+ blk.strip!
620
+ if blk.empty?
621
+ blk
622
+ else
623
+ code_blk = nil
624
+ blk.gsub!( /((?:\n(?:\n^ +[^\n]*)+)+)/m ) do |iblk|
625
+ flush_left iblk
626
+ blocks iblk, plain
627
+ iblk.gsub( /^(\S)/, "\t\\1" )
628
+ if plain
629
+ code_blk = iblk; ""
630
+ else
631
+ iblk
632
+ end
633
+ end
634
+
635
+ block_applied = 0
636
+ @rules.each do |rule_name|
637
+ block_applied += 1 if ( rule_name.to_s.match /^block_/ and method( rule_name ).call( blk ) )
638
+ end
639
+ if block_applied.zero?
640
+ if deep_code
641
+ blk = "\t<pre><code>#{ blk }</code></pre>"
642
+ else
643
+ blk = "\t<p>#{ blk }</p>"
644
+ end
645
+ end
646
+ # hard_break blk
647
+ blk + "\n#{ code_blk }"
648
+ end
649
+ end
650
+
651
+ end.join( "\n\n" ) )
652
+ end
653
+
654
+ def textile_bq( tag, atts, cite, content )
655
+ cite, cite_title = check_refs( cite )
656
+ cite = " cite=\"#{ cite }\"" if cite
657
+ atts = shelve( atts ) if atts
658
+ "\t<blockquote#{ cite }>\n\t\t<p#{ atts }>#{ content }</p>\n\t</blockquote>"
659
+ end
660
+
661
+ def textile_p( tag, atts, cite, content )
662
+ atts = shelve( atts ) if atts
663
+ "\t<#{ tag }#{ atts }>#{ content }</#{ tag }>"
664
+ end
665
+
666
+ alias textile_h1 textile_p
667
+ alias textile_h2 textile_p
668
+ alias textile_h3 textile_p
669
+ alias textile_h4 textile_p
670
+ alias textile_h5 textile_p
671
+ alias textile_h6 textile_p
672
+
673
+ def textile_fn_( tag, num, atts, cite, content )
674
+ atts << " id=\"fn#{ num }\""
675
+ content = "<sup>#{ num }</sup> #{ content }"
676
+ atts = shelve( atts ) if atts
677
+ "\t<p#{ atts }>#{ content }</p>"
678
+ end
679
+
680
+ BLOCK_RE = /^(([a-z]+)(\d*))(#{A}#{C})\.(?::(\S+))? (.*)$/m
681
+
682
+ def block_textile_prefix( text )
683
+ if text =~ BLOCK_RE
684
+ tag,tagpre,num,atts,cite,content = $~[1..6]
685
+ atts = pba( atts )
686
+
687
+ # pass to prefix handler
688
+ if respond_to? "textile_#{ tag }", true
689
+ text.gsub!( $&, method( "textile_#{ tag }" ).call( tag, atts, cite, content ) )
690
+ elsif respond_to? "textile_#{ tagpre }_", true
691
+ text.gsub!( $&, method( "textile_#{ tagpre }_" ).call( tagpre, num, atts, cite, content ) )
692
+ end
693
+ end
694
+ end
695
+
696
+ SETEXT_RE = /\A(.+?)\n([=-])[=-]* *$/m
697
+ def block_markdown_setext( text )
698
+ if text =~ SETEXT_RE
699
+ tag = if $2 == "="; "h1"; else; "h2"; end
700
+ blk, cont = "<#{ tag }>#{ $1 }</#{ tag }>", $'
701
+ blocks cont
702
+ text.replace( blk + cont )
703
+ end
704
+ end
705
+
706
+ ATX_RE = /\A(\#{1,6}) # $1 = string of #'s
707
+ [ ]*
708
+ (.+?) # $2 = Header text
709
+ [ ]*
710
+ \#* # optional closing #'s (not counted)
711
+ $/x
712
+ def block_markdown_atx( text )
713
+ if text =~ ATX_RE
714
+ tag = "h#{ $1.length }"
715
+ blk, cont = "<#{ tag }>#{ $2 }</#{ tag }>\n\n", $'
716
+ blocks cont
717
+ text.replace( blk + cont )
718
+ end
719
+ end
720
+
721
+ MARKDOWN_BQ_RE = /\A(^ *> ?.+$(.+\n)*\n*)+/m
722
+
723
+ def block_markdown_bq( text )
724
+ text.gsub!( MARKDOWN_BQ_RE ) do |blk|
725
+ blk.gsub!( /^ *> ?/, '' )
726
+ flush_left blk
727
+ blocks blk
728
+ blk.gsub!( /^(\S)/, "\t\\1" )
729
+ "<blockquote>\n#{ blk }\n</blockquote>\n\n"
730
+ end
731
+ end
732
+
733
+ MARKDOWN_RULE_RE = /^(#{
734
+ ['*', '-', '_'].collect { |ch| '( ?' + Regexp::quote( ch ) + ' ?){3,}' }.join( '|' )
735
+ })$/
736
+
737
+ def block_markdown_rule( text )
738
+ text.gsub!( MARKDOWN_RULE_RE ) do |blk|
739
+ "<hr />"
740
+ end
741
+ end
742
+
743
+ # XXX TODO XXX
744
+ def block_markdown_lists( text )
745
+ end
746
+
747
+ def inline_textile_span( text )
748
+ QTAGS.each do |qtag_rc, ht, qtag_re, rtype|
749
+ text.gsub!( qtag_re ) do |m|
750
+
751
+ case rtype
752
+ when :limit
753
+ sta,qtag,atts,cite,content = $~[1..5]
754
+ else
755
+ qtag,atts,cite,content = $~[1..4]
756
+ sta = ''
757
+ end
758
+ atts = pba( atts )
759
+ atts << " cite=\"#{ cite }\"" if cite
760
+ atts = shelve( atts ) if atts
761
+
762
+ "#{ sta }<#{ ht }#{ atts }>#{ content }</#{ ht }>"
763
+
764
+ end
765
+ end
766
+ end
767
+
768
+ LINK_RE = /
769
+ ([\s\[{(]|[#{PUNCT}])? # $pre
770
+ " # start
771
+ (#{C}) # $atts
772
+ ([^"]+?) # $text
773
+ \s?
774
+ (?:\(([^)]+?)\)(?="))? # $title
775
+ ":
776
+ (\S+?) # $url
777
+ (\/)? # $slash
778
+ ([^\w\/;]*?) # $post
779
+ (?=<|\s|$)
780
+ /x
781
+
782
+ def inline_textile_link( text )
783
+ text.gsub!( LINK_RE ) do |m|
784
+ pre,atts,text,title,url,slash,post = $~[1..7]
785
+
786
+ url, url_title = check_refs( url )
787
+ title ||= url_title
788
+
789
+ atts = pba( atts )
790
+ atts = " href=\"#{ url }#{ slash }\"#{ atts }"
791
+ atts << " title=\"#{ title }\"" if title
792
+ atts = shelve( atts ) if atts
793
+
794
+ "#{ pre }<a#{ atts }>#{ text }</a>#{ post }"
795
+ end
796
+ end
797
+
798
+ MARKDOWN_REFLINK_RE = /
799
+ \[([^\[\]]+)\] # $text
800
+ [ ]? # opt. space
801
+ (?:\n[ ]*)? # one optional newline followed by spaces
802
+ \[(.*?)\] # $id
803
+ /x
804
+
805
+ def inline_markdown_reflink( text )
806
+ text.gsub!( MARKDOWN_REFLINK_RE ) do |m|
807
+ text, id = $~[1..2]
808
+
809
+ if id.empty?
810
+ url, title = check_refs( text )
811
+ else
812
+ url, title = check_refs( id )
813
+ end
814
+
815
+ atts = " href=\"#{ url }\""
816
+ atts << " title=\"#{ title }\"" if title
817
+ atts = shelve( atts )
818
+
819
+ "<a#{ atts }>#{ text }</a>"
820
+ end
821
+ end
822
+
823
+ MARKDOWN_LINK_RE = /
824
+ \[([^\[\]]+)\] # $text
825
+ \( # open paren
826
+ [ \t]* # opt space
827
+ <?(.+?)>? # $href
828
+ [ \t]* # opt space
829
+ (?: # whole title
830
+ (['"]) # $quote
831
+ (.*?) # $title
832
+ \3 # matching quote
833
+ )? # title is optional
834
+ \)
835
+ /x
836
+
837
+ def inline_markdown_link( text )
838
+ text.gsub!( MARKDOWN_LINK_RE ) do |m|
839
+ text, url, quote, title = $~[1..4]
840
+
841
+ atts = " href=\"#{ url }\""
842
+ atts << " title=\"#{ title }\"" if title
843
+ atts = shelve( atts )
844
+
845
+ "<a#{ atts }>#{ text }</a>"
846
+ end
847
+ end
848
+
849
+ TEXTILE_REFS_RE = /(^ *)\[([^\n]+?)\](#{HYPERLINK})(?=\s|$)/
850
+ MARKDOWN_REFS_RE = /(^ *)\[([^\n]+?)\]:\s+<?(#{HYPERLINK})>?(?:\s+"((?:[^"]|\\")+)")?(?=\s|$)/m
851
+
852
+ def refs( text )
853
+ @rules.each do |rule_name|
854
+ method( rule_name ).call( text ) if rule_name.to_s.match /^refs_/
855
+ end
856
+ end
857
+
858
+ def refs_textile( text )
859
+ text.gsub!( TEXTILE_REFS_RE ) do |m|
860
+ flag, url = $~[2..3]
861
+ @urlrefs[flag.downcase] = [url, nil]
862
+ nil
863
+ end
864
+ end
865
+
866
+ def refs_markdown( text )
867
+ text.gsub!( MARKDOWN_REFS_RE ) do |m|
868
+ flag, url = $~[2..3]
869
+ title = $~[6]
870
+ @urlrefs[flag.downcase] = [url, title]
871
+ nil
872
+ end
873
+ end
874
+
875
+ def check_refs( text )
876
+ ret = @urlrefs[text.downcase] if text
877
+ ret || [text, nil]
878
+ end
879
+
880
+ IMAGE_RE = /
881
+ (<p>|.|^) # start of line?
882
+ \! # opening
883
+ (\<|\=|\>)? # optional alignment atts
884
+ (#{C}) # optional style,class atts
885
+ (?:\. )? # optional dot-space
886
+ ([^\s(!]+?) # presume this is the src
887
+ \s? # optional space
888
+ (?:\(((?:[^\(\)]|\([^\)]+\))+?)\))? # optional title
889
+ \! # closing
890
+ (?::#{ HYPERLINK })? # optional href
891
+ /x
892
+
893
+ def inline_textile_image( text )
894
+ text.gsub!( IMAGE_RE ) do |m|
895
+ stln,algn,atts,url,title,href,href_a1,href_a2 = $~[1..8]
896
+ atts = pba( atts )
897
+ atts = " src=\"#{ url }\"#{ atts }"
898
+ atts << " title=\"#{ title }\"" if title
899
+ atts << " alt=\"#{ title }\""
900
+ # size = @getimagesize($url);
901
+ # if($size) $atts.= " $size[3]";
902
+
903
+ href, alt_title = check_refs( href ) if href
904
+ url, url_title = check_refs( url )
905
+
906
+ out = ''
907
+ out << "<a#{ shelve( " href=\"#{ href }\"" ) }>" if href
908
+ out << "<img#{ shelve( atts ) } />"
909
+ out << "</a>#{ href_a1 }#{ href_a2 }" if href
910
+
911
+ if algn
912
+ algn = h_align( algn )
913
+ if stln == "<p>"
914
+ out = "<p style=\"float:#{ algn }\">#{ out }"
915
+ else
916
+ out = "#{ stln }<div style=\"float:#{ algn }\">#{ out }</div>"
917
+ end
918
+ else
919
+ out = stln + out
920
+ end
921
+
922
+ out
923
+ end
924
+ end
925
+
926
+ def shelve( val )
927
+ @shelf << val
928
+ " :redsh##{ @shelf.length }:"
929
+ end
930
+
931
+ def retrieve( text )
932
+ @shelf.each_with_index do |r, i|
933
+ text.gsub!( " :redsh##{ i + 1 }:", r )
934
+ end
935
+ end
936
+
937
+ def incoming_entities( text )
938
+ ## turn any incoming ampersands into a dummy character for now.
939
+ ## This uses a negative lookahead for alphanumerics followed by a semicolon,
940
+ ## implying an incoming html entity, to be skipped
941
+
942
+ text.gsub!( /&(?![#a-z0-9]+;)/i, "x%x%" )
943
+ end
944
+
945
+ def no_textile( text )
946
+ text.gsub!( /(^|\s)==([^=]+.*?)==(\s|$)?/,
947
+ '\1<notextile>\2</notextile>\3' )
948
+ text.gsub!( /^ *==([^=]+.*?)==/m,
949
+ '\1<notextile>\2</notextile>\3' )
950
+ end
951
+
952
+ def clean_white_space( text )
953
+ # normalize line breaks
954
+ text.gsub!( /\r\n/, "\n" )
955
+ text.gsub!( /\r/, "\n" )
956
+ text.gsub!( /\t/, ' ' )
957
+ text.gsub!( /^ +$/, '' )
958
+ text.gsub!( /\n{3,}/, "\n\n" )
959
+ text.gsub!( /"$/, "\" " )
960
+
961
+ # if entire document is indented, flush
962
+ # to the left side
963
+ flush_left text
964
+ end
965
+
966
+ def flush_left( text )
967
+ indt = 0
968
+ if text =~ /^ /
969
+ while text !~ /^ {#{indt}}\S/
970
+ indt += 1
971
+ end unless text.empty?
972
+ if indt.nonzero?
973
+ text.gsub!( /^ {#{indt}}/, '' )
974
+ end
975
+ end
976
+ end
977
+
978
+ def footnote_ref( text )
979
+ text.gsub!( /\b\[([0-9]+?)\](\s)?/,
980
+ '<sup><a href="#fn\1">\1</a></sup>\2' )
981
+ end
982
+
983
+ OFFTAGS = /(code|pre|kbd|notextile)/
984
+ OFFTAG_MATCH = /(?:(<\/#{ OFFTAGS }>)|(<#{ OFFTAGS }[^>]*>))(.*?)(?=<\/?#{ OFFTAGS }|\Z)/mi
985
+ OFFTAG_OPEN = /<#{ OFFTAGS }/
986
+ OFFTAG_CLOSE = /<\/?#{ OFFTAGS }/
987
+ HASTAG_MATCH = /(<\/?\w[^\n]*?>)/m
988
+ ALLTAG_MATCH = /(<\/?\w[^\n]*?>)|.*?(?=<\/?\w[^\n]*?>|$)/m
989
+
990
+ def glyphs_textile( text, level = 0 )
991
+ if text !~ HASTAG_MATCH
992
+ pgl text
993
+ footnote_ref text
994
+ else
995
+ codepre = 0
996
+ text.gsub!( ALLTAG_MATCH ) do |line|
997
+ ## matches are off if we're between <code>, <pre> etc.
998
+ if $1
999
+ if line =~ OFFTAG_OPEN
1000
+ codepre += 1
1001
+ elsif line =~ OFFTAG_CLOSE
1002
+ codepre -= 1
1003
+ codepre = 0 if codepre < 0
1004
+ end
1005
+ elsif codepre.zero?
1006
+ glyphs_textile( line, level + 1 )
1007
+ else
1008
+ htmlesc( line, :NoQuotes )
1009
+ end
1010
+ # p [level, codepre, line]
1011
+
1012
+ line
1013
+ end
1014
+ end
1015
+ end
1016
+
1017
+ def rip_offtags( text )
1018
+ if text =~ /<.*>/
1019
+ ## strip and encode <pre> content
1020
+ codepre, used_offtags = 0, {}
1021
+ text.gsub!( OFFTAG_MATCH ) do |line|
1022
+ if $3
1023
+ offtag, aftertag = $4, $5
1024
+ codepre += 1
1025
+ used_offtags[offtag] = true
1026
+ if codepre - used_offtags.length > 0
1027
+ htmlesc( line, :NoQuotes ) unless used_offtags['notextile']
1028
+ @pre_list.last << line
1029
+ line = ""
1030
+ else
1031
+ htmlesc( aftertag, :NoQuotes ) if aftertag and not used_offtags['notextile']
1032
+ line = "<redpre##{ @pre_list.length }>"
1033
+ @pre_list << "#{ $3 }#{ aftertag }"
1034
+ end
1035
+ elsif $1 and codepre > 0
1036
+ if codepre - used_offtags.length > 0
1037
+ htmlesc( line, :NoQuotes ) unless used_offtags['notextile']
1038
+ @pre_list.last << line
1039
+ line = ""
1040
+ end
1041
+ codepre -= 1 unless codepre.zero?
1042
+ used_offtags = {} if codepre.zero?
1043
+ end
1044
+ line
1045
+ end
1046
+ end
1047
+ text
1048
+ end
1049
+
1050
+ def smooth_offtags( text )
1051
+ unless @pre_list.empty?
1052
+ ## replace <pre> content
1053
+ text.gsub!( /<redpre#(\d+)>/ ) { @pre_list[$1.to_i] }
1054
+ end
1055
+ end
1056
+
1057
+ def inline( text )
1058
+ [/^inline_/, /^glyphs_/].each do |meth_re|
1059
+ @rules.each do |rule_name|
1060
+ method( rule_name ).call( text ) if rule_name.to_s.match( meth_re )
1061
+ end
1062
+ end
1063
+ end
1064
+
1065
+ def h_align( text )
1066
+ H_ALGN_VALS[text]
1067
+ end
1068
+
1069
+ def v_align( text )
1070
+ V_ALGN_VALS[text]
1071
+ end
1072
+
1073
+ def textile_popup_help( name, windowW, windowH )
1074
+ ' <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 />'
1075
+ end
1076
+
1077
+ # HTML cleansing stuff
1078
+ BASIC_TAGS = {
1079
+ 'a' => ['href', 'title'],
1080
+ 'img' => ['src', 'alt', 'title'],
1081
+ 'br' => [],
1082
+ 'i' => nil,
1083
+ 'u' => nil,
1084
+ 'b' => nil,
1085
+ 'pre' => nil,
1086
+ 'kbd' => nil,
1087
+ 'code' => ['lang'],
1088
+ 'cite' => nil,
1089
+ 'strong' => nil,
1090
+ 'em' => nil,
1091
+ 'ins' => nil,
1092
+ 'sup' => nil,
1093
+ 'sub' => nil,
1094
+ 'del' => nil,
1095
+ 'table' => nil,
1096
+ 'tr' => nil,
1097
+ 'td' => ['colspan', 'rowspan'],
1098
+ 'th' => nil,
1099
+ 'ol' => nil,
1100
+ 'ul' => nil,
1101
+ 'li' => nil,
1102
+ 'p' => nil,
1103
+ 'h1' => nil,
1104
+ 'h2' => nil,
1105
+ 'h3' => nil,
1106
+ 'h4' => nil,
1107
+ 'h5' => nil,
1108
+ 'h6' => nil,
1109
+ 'blockquote' => ['cite']
1110
+ }
1111
+
1112
+ def clean_html( text, tags = BASIC_TAGS )
1113
+ text.gsub!( /<!\[CDATA\[/, '' )
1114
+ text.gsub!( /<(\/*)(\w+)([^>]*)>/ ) do
1115
+ raw = $~
1116
+ tag = raw[2].downcase
1117
+ if tags.has_key? tag
1118
+ pcs = [tag]
1119
+ tags[tag].each do |prop|
1120
+ ['"', "'", ''].each do |q|
1121
+ q2 = ( q != '' ? q : '\s' )
1122
+ if raw[3] =~ /#{prop}\s*=\s*#{q}([^#{q2}]+)#{q}/i
1123
+ attrv = $1
1124
+ next if prop == 'src' and attrv =~ %r{^(?!http)\w+:}
1125
+ pcs << "#{prop}=\"#{$1.gsub('"', '\\"')}\""
1126
+ break
1127
+ end
1128
+ end
1129
+ end if tags[tag]
1130
+ "<#{raw[1]}#{pcs.join " "}>"
1131
+ else
1132
+ " "
1133
+ end
1134
+ end
1135
+ end
1136
+ end
1137
+
data/lib/textilize.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'textilize/helper'
2
+ ActiveSupport.on_load(:action_view) do
3
+ include Textilize::Helper
4
+ end
5
+
@@ -0,0 +1,66 @@
1
+ #mainly extract from Rails2.
2
+ module Textilize
3
+ module Helper
4
+ require 'RedCloth'
5
+ # Returns the text with all the Textile[http://www.textism.com/tools/textile] codes turned into HTML tags.
6
+ #
7
+ # You can learn more about Textile's syntax at its website[http://www.textism.com/tools/textile].
8
+ # <i>This method is only available if RedCloth[http://whytheluckystiff.net/ruby/redcloth/]
9
+ # is available</i>.
10
+ #
11
+ # ==== Examples
12
+ # textilize("*This is Textile!* Rejoice!")
13
+ # # => "<p><strong>This is Textile!</strong> Rejoice!</p>"
14
+ #
15
+ # textilize("I _love_ ROR(Ruby on Rails)!")
16
+ # # => "<p>I <em>love</em> <acronym title="Ruby on Rails">ROR</acronym>!</p>"
17
+ #
18
+ # textilize("h2. Textile makes markup -easy- simple!")
19
+ # # => "<h2>Textile makes markup <del>easy</del> simple!</h2>"
20
+ #
21
+ # textilize("Visit the Rails website "here":http://www.rubyonrails.org/.)
22
+ # # => "<p>Visit the Rails website <a href="http://www.rubyonrails.org/">here</a>.</p>"
23
+ #
24
+ # textilize("This is worded <strong>strongly</strong>")
25
+ # # => "<p>This is worded <strong>strongly</strong></p>"
26
+ #
27
+ # textilize("This is worded <strong>strongly</strong>", :filter_html)
28
+ # # => "<p>This is worded &lt;strong&gt;strongly&lt;/strong&gt;</p>"
29
+ def textilize(text, *options)
30
+ text = sanitize(text) unless text.html_safe?
31
+ text.blank? ? "" : RedCloth.new(text, options).to_html.html_safe
32
+ end
33
+
34
+ # Returns the text with all the Textile codes turned into HTML tags,
35
+ # but without the bounding <p> tag that RedCloth adds.
36
+ #
37
+ # You can learn more about Textile's syntax at its website[http://www.textism.com/tools/textile].
38
+ # <i>This method is requires RedCloth[http://whytheluckystiff.net/ruby/redcloth/]
39
+ # to be available</i>.
40
+ #
41
+ # ==== Examples
42
+ # textilize_without_paragraph("*This is Textile!* Rejoice!")
43
+ # # => "<strong>This is Textile!</strong> Rejoice!"
44
+ #
45
+ # textilize_without_paragraph("I _love_ ROR(Ruby on Rails)!")
46
+ # # => "I <em>love</em> <acronym title="Ruby on Rails">ROR</acronym>!"
47
+ #
48
+ # textilize_without_paragraph("h2. Textile makes markup -easy- simple!")
49
+ # # => "<h2>Textile makes markup <del>easy</del> simple!</h2>"
50
+ #
51
+ # textilize_without_paragraph("Visit the Rails website "here":http://www.rubyonrails.org/.)
52
+ # # => "Visit the Rails website <a href="http://www.rubyonrails.org/">here</a>."
53
+ def textilize_without_paragraph(text, *options)
54
+ textiled = textilize(text, *options)
55
+ if textiled[0..2] == "<p>"
56
+ textiled = textiled[3..-1]
57
+ end
58
+ if textiled[-4..-1] == "</p>"
59
+ textiled = textiled[0..-5]
60
+ end
61
+ textiled.html_safe
62
+ end
63
+
64
+ end
65
+ end
66
+
@@ -0,0 +1,4 @@
1
+ module Textilize
2
+ VERSION = '0.0.2'
3
+ end
4
+
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: textilize
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Mysen Huang
9
+ - Adeh DeSandies
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-07-05 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rake
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ description:
32
+ email: mysen@kudelabs.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - lib/redcloth.rb
38
+ - lib/textilize/helper.rb
39
+ - lib/textilize/version.rb
40
+ - lib/textilize.rb
41
+ - LICENSE
42
+ - README.md
43
+ homepage: http://github.com/kudelabs/textilize
44
+ licenses: []
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubyforge_project:
63
+ rubygems_version: 1.8.24
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: Gem containing the textilize and textilize_without_paragraph methods removed
67
+ from Rails without C Extensions.
68
+ test_files: []