kron4eg-wikicloth 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
File without changes
@@ -0,0 +1,23 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the wikicloth plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the wikicloth plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'WikiCloth'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + "/rails/init.rb"
@@ -0,0 +1,43 @@
1
+ module ExtendedString
2
+
3
+ def blank?
4
+ respond_to?(:empty?) ? empty? : !self
5
+ end
6
+
7
+ def to_slug
8
+ self.gsub(/\W+/, '-').gsub(/^-+/,'').gsub(/-+$/,'').downcase
9
+ end
10
+
11
+ def auto_link
12
+ url_check = Regexp.new( '(^|[\n ])([\w]+?://[\w]+[^ \"\r\n\t<]*)', Regexp::MULTILINE | Regexp::IGNORECASE )
13
+ www_check = Regexp.new( '(^|[\n ])((www)\.[^ \"\t\n\r<]*)', Regexp::MULTILINE | Regexp::IGNORECASE )
14
+ self.gsub!(url_check, '\1<a href="\2">\2</a>')
15
+ self.gsub!(www_check, '\1<a href="http://\2">\2</a>')
16
+ to_s
17
+ end
18
+
19
+ def dump()
20
+ ret = to_s
21
+ delete!(to_s)
22
+ ret
23
+ end
24
+
25
+ def smart_split(char)
26
+ ret = []
27
+ tmp = ""
28
+ inside = 0
29
+ to_s.each_char do |x|
30
+ if x == char && inside == 0
31
+ ret << tmp
32
+ tmp = ""
33
+ else
34
+ inside += 1 if x == "[" || x == "{" || x == "<"
35
+ inside -= 1 if x == "]" || x == "}" || x == ">"
36
+ tmp += x
37
+ end
38
+ end
39
+ ret << tmp unless tmp.empty?
40
+ ret
41
+ end
42
+
43
+ end
@@ -0,0 +1,279 @@
1
+ module WikiCloth
2
+ class WikiBuffer
3
+
4
+ def initialize(data="",options={})
5
+ @options = options
6
+ self.data = data
7
+ self.buffer_type = nil
8
+ @section_count = 0
9
+ @buffers ||= [ ]
10
+ @buffers << self
11
+ @list_data = []
12
+ end
13
+
14
+ def run_globals?
15
+ true
16
+ end
17
+
18
+ def skip_html?
19
+ false
20
+ end
21
+
22
+ def data
23
+ @data ||= ""
24
+ end
25
+
26
+ def params
27
+ @params ||= [ "" ]
28
+ end
29
+
30
+ def buffer_type
31
+ @buffer_type
32
+ end
33
+
34
+ def to_s
35
+ "<p>" + self.params.join("\n") + "</p>"
36
+ end
37
+
38
+ def check_globals()
39
+ return false if self.class != WikiBuffer
40
+
41
+ if previous_char == "\n"
42
+ if @indent == @buffers[-1].object_id && current_char != " "
43
+ # close pre tag
44
+ cc_temp = current_char
45
+ "</pre>".each_char { |c| self.add_char(c) }
46
+ # get the parser back on the right track
47
+ "\n#{cc_temp}".each_char { |c| @buffers[-1].add_char(c) }
48
+ @indent = nil
49
+ return true
50
+ end
51
+ if current_char == " " && @indent.nil? && @buffers[-1].class != WikiBuffer::HTMLElement
52
+ "<pre> ".each_char { |c| @buffers[-1].add_char(c) }
53
+ @indent = @buffers[-1].object_id
54
+ return true
55
+ end
56
+ end
57
+
58
+ if @buffers[-1].run_globals?
59
+ # new html tag
60
+ if @check_new_tag == true && current_char =~ /([a-z])/ && !@buffers[-1].skip_html?
61
+ @buffers[-1].data.chop!
62
+ parent = @buffers[-1].element_name if @buffers[-1].class == WikiBuffer::HTMLElement
63
+ @buffers << WikiBuffer::HTMLElement.new("",@options,parent)
64
+ end
65
+ @check_new_tag = current_char == '<' ? true : false
66
+
67
+ # global
68
+ case
69
+ # start variable
70
+ when previous_char == '{' && current_char == '{'
71
+ @buffers[-1].data.chop!
72
+ @buffers << WikiBuffer::Var.new("",@options)
73
+ return true
74
+
75
+ # start link
76
+ when current_char == '[' && previous_char != '['
77
+ @buffers << WikiBuffer::Link.new("",@options)
78
+ return true
79
+
80
+ # start table
81
+ when previous_char == '{' && current_char == "|"
82
+ @buffers[-1].data.chop!
83
+ @buffers << WikiBuffer::Table.new("",@options)
84
+ return true
85
+
86
+ end
87
+ end
88
+
89
+ return false
90
+ end
91
+
92
+ def add_char(c)
93
+ self.previous_char = self.current_char
94
+ self.current_char = c
95
+
96
+ if self.check_globals() == false
97
+ case
98
+ when @buffers.size == 1
99
+ return self.new_char()
100
+ when @buffers[-1].add_char(c) == false && self.class == WikiBuffer
101
+ tmp = @buffers.pop
102
+ @buffers[-1].data += tmp.to_s
103
+ # any data left in the buffer we feed into the parent
104
+ unless tmp.data.blank?
105
+ tmp.data.each_char { |c| self.add_char(c) }
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ protected
112
+ # only executed in the default state
113
+ def new_char()
114
+ case
115
+ when current_char == "\n"
116
+ if @options[:extended_markup] == true
117
+ self.data.gsub!(/---([^-]+)---/,"<strike>\\1</strike>")
118
+ self.data.gsub!(/_([^_]+)_/,"<u>\\1</u>")
119
+ end
120
+ self.data.gsub!(/__([a-zA-Z0-9]+)__/) { |r|
121
+ case $1
122
+ when "NOEDITSECTION"
123
+ @noeditsection = true
124
+ end
125
+ ""
126
+ }
127
+ self.data.gsub!(/^([-]{4,})/) { |r| "<hr />" }
128
+ self.data.gsub!(/^([=]{1,6})\s*(.*?)\s*(\1)/) { |r|
129
+ @section_count += 1
130
+ "<h#{$1.length}>" + (@noeditsection == true ? "" :
131
+ "<span class=\"editsection\">[<a href=\"" + @options[:link_handler].section_link(@section_count) +
132
+ "\" title=\"Edit section: #{$2}\">edit</a>]</span>") +
133
+ " <span class=\"mw-headline\">#{$2}</span></h#{$1.length}>"
134
+ }
135
+ self.data.gsub!(/([\']{2,5})(.*?)(\1)/) { |r|
136
+ tmp = "<i>#{$2}</i>" if $1.length == 2
137
+ tmp = "<b>#{$2}</b>" if $1.length == 3
138
+ tmp = "<b>'#{$2}'</b>" if $1.length == 4
139
+ tmp = "<b><i>#{$2}</i></b>" if $1.length == 5
140
+ tmp
141
+ }
142
+ lines = self.data.split("\n")
143
+ self.data = ""
144
+ for line in lines
145
+ if !@list_data.empty? && (line.blank? || line =~ /^([^#\*:;]+)/)
146
+ tmp = ""
147
+ @list_data.reverse!
148
+ @list_data.each { |x| tmp += "</" + list_inner_tag_for(x) + "></#{list_tag_for(x)}>" }
149
+ line = "#{tmp} #{line}"
150
+ @list_data = []
151
+ end
152
+ line.gsub!(/^([#\*:;]+)(.*)$/) { |r|
153
+ cdata = []
154
+ tmp = ""
155
+ $1.each_char { |c| cdata << c }
156
+ if @list_data.empty?
157
+ tmp += "<#{list_tag_for(cdata[0])}>"
158
+ cdata[1..-1].each { |x| tmp += "<" + list_inner_tag_for(cdata[0]) + "><#{list_tag_for(x)}>" } if cdata.size > 1
159
+ else
160
+ case
161
+ when cdata.size > @list_data.size
162
+ i = cdata.size-@list_data.size
163
+ cdata[-i,i].each { |x| tmp += "<#{list_tag_for(x)}>" }
164
+ when cdata.size < @list_data.size
165
+ i = @list_data.size-cdata.size
166
+ nlist = @list_data[-i,i].reverse
167
+ nlist.each { |x| tmp += "</" + list_inner_tag_for(x) + "></#{list_tag_for(x)}>" }
168
+ tmp += "</#{list_inner_tag_for(cdata.last)}>"
169
+ else
170
+ if cdata != @list_data
171
+ # FIXME: this will only work if the change depth is one level
172
+ unless (@list_data.last == ';' || @list_data.last == ':') && (cdata.last == ';' || cdata.last == ':')
173
+ tmp += "</#{list_tag_for(@list_data.pop)}>"
174
+ tmp += "<#{list_tag_for(cdata.last)}>"
175
+ end
176
+ else
177
+ tmp += "</" + list_inner_tag_for(@list_data.last) + ">"
178
+ end
179
+ end
180
+ end
181
+ # FIXME: still probably does not detect the : properly
182
+ peices = cdata.last == ";" ? $2.smart_split(":") : [ $2 ]
183
+ if peices.size > 1
184
+ tmp += "<#{list_inner_tag_for(cdata.last)}>#{peices[0]}</#{list_inner_tag_for(cdata.last)}>"
185
+ tmp += "<dd>#{peices[1..-1].join(":")}</dd>"
186
+ cdata[-1] = ":"
187
+ else
188
+ tmp += "<#{list_inner_tag_for(cdata.last)}>#{peices[0]}"
189
+ end
190
+ @list_data = cdata
191
+ tmp
192
+ }
193
+ self.data += line + "\n"
194
+ end
195
+
196
+ self.data = "</p><p>" if self.data.blank?
197
+
198
+ self.params << self.data.auto_link
199
+ self.data = ""
200
+ else
201
+ self.data += current_char
202
+ end
203
+ return true
204
+ end
205
+
206
+ def name_current_param()
207
+ params[-1] = { :value => "", :name => params[-1] } unless params[-1].kind_of?(Hash) || params[-1].nil?
208
+ end
209
+
210
+ def current_param=(val)
211
+ unless self.params[-1].nil? || self.params[-1].kind_of?(String)
212
+ self.params[-1][:value] = val
213
+ else
214
+ self.params[-1] = val
215
+ end
216
+ end
217
+
218
+ def params=(val)
219
+ @params = val
220
+ end
221
+
222
+ def buffer_type=(val)
223
+ @buffer_type = val
224
+ end
225
+
226
+ def data=(val)
227
+ @data = val
228
+ end
229
+
230
+ def current_char=(val)
231
+ @current_char = val
232
+ end
233
+
234
+ def current_char
235
+ @current_char ||= ""
236
+ end
237
+
238
+ def previous_char=(val)
239
+ @previous_char = val
240
+ end
241
+
242
+ def previous_char
243
+ @previous_char
244
+ end
245
+
246
+ def current_line=(val)
247
+ @current_line = val
248
+ end
249
+
250
+ def current_line
251
+ @current_line ||= ""
252
+ end
253
+
254
+ def list_tag_for(tag)
255
+ case tag
256
+ when "#" then "ol"
257
+ when "*" then "ul"
258
+ when ";" then "dl"
259
+ when ":" then "dl"
260
+ end
261
+ end
262
+
263
+ def list_inner_tag_for(tag)
264
+ case tag
265
+ when "#" then "li"
266
+ when "*" then "li"
267
+ when ";" then "dt"
268
+ when ":" then "dd"
269
+ end
270
+ end
271
+
272
+ end
273
+
274
+ end
275
+
276
+ require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer", "html_element")
277
+ require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer", "table")
278
+ require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer", "var")
279
+ require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer", "link")
@@ -0,0 +1,237 @@
1
+ require 'rubygems'
2
+ require 'builder'
3
+
4
+ module WikiCloth
5
+
6
+ class WikiBuffer::HTMLElement < WikiBuffer
7
+
8
+ ALLOWED_ELEMENTS = ['a','b','i','div','span','sup','sub','strike','s','u','font','big','ref','tt','del',
9
+ 'small','blockquote','strong','pre','code','references','ol','li','ul','dd','dt','dl','center',
10
+ 'h2','h3','h4','h5','h6']
11
+ ALLOWED_ATTRIBUTES = ['id','name','style','class','href','start','value']
12
+ ESCAPED_TAGS = [ 'nowiki', 'pre', 'code' ]
13
+ SHORT_TAGS = [ 'meta','br','hr','img' ]
14
+ NO_NEED_TO_CLOSE = ['li','p'] + SHORT_TAGS
15
+
16
+ def initialize(d="",options={},check=nil)
17
+ super("",options)
18
+ self.buffer_type = "Element"
19
+ @in_quotes = false
20
+ @in_single_quotes = false
21
+ @start_tag = 1
22
+ @tag_check = check unless check.nil?
23
+ end
24
+
25
+ def run_globals?
26
+ return ESCAPED_TAGS.include?(self.element_name) ? false : true
27
+ end
28
+
29
+ def to_s
30
+ if NO_NEED_TO_CLOSE.include?(self.element_name)
31
+ return "<#{self.element_name} />" if SHORT_TAGS.include?(self.element_name)
32
+ return "</#{self.element_name}><#{self.element_name}>" if @tag_check == self.element_name
33
+ end
34
+
35
+ if ESCAPED_TAGS.include?(self.element_name)
36
+ # escape all html inside this element
37
+ self.element_content = self.element_content.gsub('<','&lt;').gsub('>','&gt;')
38
+ # hack to fix <code><nowiki> nested mess
39
+ self.element_content = self.element_content.gsub(/&lt;[\/]*\s*nowiki\s*&gt;/,'')
40
+ end
41
+
42
+ lhandler = @options[:link_handler]
43
+ case self.element_name
44
+ when "ref"
45
+ self.element_name = "sup"
46
+ named_ref = self.name_attribute
47
+ ref = lhandler.find_reference_by_name(named_ref) unless named_ref.nil?
48
+ if ref.nil?
49
+ lhandler.references << { :name => named_ref, :value => self.element_content, :count => 0 }
50
+ ref = lhandler.references.last
51
+ end
52
+ ref_id = (named_ref.nil? ? "" : "#{named_ref}_") + "#{lhandler.reference_index(ref)}-#{ref[:count]}"
53
+ self.params << { :name => "id", :value => "cite_ref-#{ref_id}" }
54
+ self.params << { :name => "class", :value => "reference" }
55
+ self.element_content = "[<a href=\"#cite_note-" + (named_ref.nil? ? "" : "#{named_ref}_") +
56
+ "#{lhandler.reference_index(ref)}\">#{lhandler.reference_index(ref)}</a>]"
57
+ ref[:count] += 1
58
+ when "references"
59
+ ref_count = 0
60
+ self.element_name = "ol"
61
+ self.element_content = lhandler.references.collect { |r|
62
+ ref_count += 1
63
+ ref_name = (r[:name].nil? ? "" : r[:name].to_slug + "_")
64
+ ret = "<li id=\"cite_note-#{ref_name}#{ref_count}\"><b>"
65
+ 1.upto(r[:count]) { |x| ret += "<a href=\"#cite_ref-#{ref_name}#{ref_count}-#{x-1}\">" +
66
+ (r[:count] == 1 ? "^" : (x-1).to_s(26).tr('0-9a-p', 'a-z')) + "</a> " }
67
+ ret += "</b> #{r[:value]}</li>"
68
+ }.to_s
69
+ when "nowiki"
70
+ return self.element_content
71
+ end
72
+
73
+ tmp = elem.tag!(self.element_name, self.element_attributes) { |x| x << self.element_content }
74
+ unless ALLOWED_ELEMENTS.include?(self.element_name)
75
+ tmp.gsub!(/[\-!\|&"\{\}\[\]]/) { |r| self.escape_char(r) }
76
+ return tmp.gsub('<', '&lt;').gsub('>', '&gt;')
77
+ end
78
+ tmp
79
+ end
80
+
81
+ def name_attribute
82
+ params.each { |p| return p[:value].to_slug if p.kind_of?(Hash) && p[:name] == "name" }
83
+ return nil
84
+ end
85
+
86
+ def element_attributes
87
+ attr = {}
88
+ params.each { |p| attr[p[:name]] = p[:value] if p.kind_of?(Hash) }
89
+ if ALLOWED_ELEMENTS.include?(self.element_name.strip.downcase)
90
+ attr.delete_if { |key,value| !ALLOWED_ATTRIBUTES.include?(key.strip) }
91
+ end
92
+ return attr
93
+ end
94
+
95
+ def element_name
96
+ @ename ||= ""
97
+ end
98
+
99
+ def element_content
100
+ @econtent ||= ""
101
+ end
102
+
103
+ protected
104
+
105
+ def escape_char(c)
106
+ c = case c
107
+ when '-' then '&#45;'
108
+ when '!' then '&#33;'
109
+ when '|' then '&#124;'
110
+ when '&' then '&amp;'
111
+ when '"' then '&quot;'
112
+ when '{' then '&#123;'
113
+ when '}' then '&#125;'
114
+ when '[' then '&#91;'
115
+ when ']' then '&#93;'
116
+ when '*' then '&#42;'
117
+ when '#' then '&#35;'
118
+ when ':' then '&#58;'
119
+ when ';' then '&#59;'
120
+ when "'" then '&#39;'
121
+ when '=' then '&#61;'
122
+ else
123
+ c
124
+ end
125
+ return c
126
+ end
127
+
128
+ def elem
129
+ Builder::XmlMarkup.new
130
+ end
131
+
132
+ def element_name=(val)
133
+ @ename = val
134
+ end
135
+
136
+ def element_content=(val)
137
+ @econtent = val
138
+ end
139
+
140
+ def in_quotes?
141
+ @in_quotes || @in_single_quotes ? true : false
142
+ end
143
+
144
+ def new_char()
145
+ case
146
+ # tag name
147
+ when @start_tag == 1 && current_char == ' '
148
+ self.element_name = self.data.strip.downcase
149
+ self.data = ""
150
+ @start_tag = 2
151
+
152
+ # tag is closed <tag/> no attributes
153
+ when @start_tag == 1 && previous_char == '/' && current_char == '>'
154
+ self.data.chop!
155
+ self.element_name = self.data.strip.downcase
156
+ self.data = ""
157
+ @start_tag = 0
158
+ return false
159
+
160
+ # open tag
161
+ when @start_tag == 1 && previous_char != '/' && current_char == '>'
162
+ self.element_name = self.data.strip.downcase
163
+ self.data = ""
164
+ @start_tag = 0
165
+ return false if SHORT_TAGS.include?(self.element_name)
166
+ return false if self.element_name == @tag_check && NO_NEED_TO_CLOSE.include?(self.element_name)
167
+
168
+ # new tag attr
169
+ when @start_tag == 2 && current_char == ' ' && self.in_quotes? == false
170
+ self.current_param = self.data
171
+ self.data = ""
172
+ self.params << ""
173
+
174
+ # tag attribute name
175
+ when @start_tag == 2 && current_char == '=' && self.in_quotes? == false
176
+ self.current_param = self.data
177
+ self.data = ""
178
+ self.name_current_param()
179
+
180
+ # tag is now open
181
+ when @start_tag == 2 && previous_char != '/' && current_char == '>'
182
+ self.current_param = self.data
183
+ self.data = ""
184
+ @start_tag = 0
185
+ return false if SHORT_TAGS.include?(self.element_name)
186
+ return false if self.element_name == @tag_check && NO_NEED_TO_CLOSE.include?(self.element_name)
187
+
188
+ # tag is closed <example/>
189
+ when @start_tag == 2 && previous_char == '/' && current_char == '>'
190
+ self.current_param = self.data.chop
191
+ self.data = ""
192
+ @start_tag = 0
193
+ return false
194
+
195
+ # in quotes
196
+ when @start_tag == 2 && current_char == "'" && previous_char != '\\' && !@in_quotes
197
+ @in_single_quotes = !@in_single_quotes
198
+
199
+ # in quotes
200
+ when @start_tag == 2 && current_char == '"' && previous_char != '\\' && !@in_single_quotes
201
+ @in_quotes = !@in_quotes
202
+
203
+ # start of a closing tag
204
+ when @start_tag == 0 && previous_char == '<' && current_char == '/'
205
+ self.element_content += self.data.chop
206
+ self.data = ""
207
+ @start_tag = 5
208
+
209
+ when @start_tag == 5 && (current_char == '>' || current_char == ' ') && !self.data.blank?
210
+ self.data = self.data.strip.downcase
211
+ if self.data == self.element_name
212
+ self.data = ""
213
+ return false
214
+ else
215
+ if @tag_check == self.data && NO_NEED_TO_CLOSE.include?(self.element_name)
216
+ self.data = "</#{self.data}>"
217
+ return false
218
+ else
219
+ self.element_content += "&lt;/#{self.data}&gt;"
220
+ @start_tag = 0
221
+ self.data = ""
222
+ end
223
+ end
224
+
225
+ else
226
+ if @start_tag == 0 && ESCAPED_TAGS.include?(self.element_name)
227
+ self.data += self.escape_char(current_char)
228
+ else
229
+ self.data += current_char
230
+ end
231
+ end
232
+ return true
233
+ end
234
+
235
+ end
236
+
237
+ end