textilize 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []