wikicloth 0.7.1 → 0.8.0

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.
@@ -1,5 +1,3 @@
1
- require 'rubygems'
2
- require 'builder'
3
1
  require 'rexml/document'
4
2
 
5
3
  module WikiCloth
@@ -11,10 +9,10 @@ class WikiBuffer::HTMLElement < WikiBuffer
11
9
  'h1','h2','h3','h4','h5','h6','p','table','tr','td','th','tbody','thead','tfoot']
12
10
  ALLOWED_ATTRIBUTES = ['src','id','name','style','class','href','start','value','colspan','align','border',
13
11
  'cellpadding','cellspacing','name','valign','color','rowspan','nowrap','title','rel','for']
14
- ESCAPED_TAGS = [ 'nowiki', 'pre', 'code' ]
12
+ ESCAPED_TAGS = [ 'nowiki','pre','code' ]
15
13
  SHORT_TAGS = [ 'meta','br','hr']
16
14
  NO_NEED_TO_CLOSE = ['li','p'] + SHORT_TAGS
17
- DISABLE_GLOBALS_FOR = ESCAPED_TAGS + [ 'math' ]
15
+ DISABLE_GLOBALS_FOR = ESCAPED_TAGS
18
16
 
19
17
  def initialize(d="",options={},check=nil)
20
18
  super("",options)
@@ -38,78 +36,41 @@ class WikiBuffer::HTMLElement < WikiBuffer
38
36
  end
39
37
  end
40
38
 
39
+ def skip_html?
40
+ return Extension.skip_html?(self.element_name) if Extension.element_exists?(self.element_name)
41
+ DISABLE_GLOBALS_FOR.include?(self.element_name) ? true : false
42
+ end
43
+
41
44
  def run_globals?
45
+ return false if self.in_template? && self.element_name == "noinclude"
46
+ return false if !self.in_template? && self.element_name == "includeonly"
47
+ return Extension.run_globals?(self.element_name) if Extension.element_exists?(self.element_name)
42
48
  return DISABLE_GLOBALS_FOR.include?(self.element_name) ? false : true
43
49
  end
44
50
 
45
- def to_s
51
+ def to_html
46
52
  if NO_NEED_TO_CLOSE.include?(self.element_name)
47
53
  return "<#{self.element_name} />" if SHORT_TAGS.include?(self.element_name)
48
54
  return "</#{self.element_name}><#{self.element_name}>" if @tag_check == self.element_name
49
55
  end
50
56
 
51
57
  if ESCAPED_TAGS.include?(self.element_name)
58
+ # remove empty first line
59
+ self.element_content = $1 if self.element_content =~ /^\s*\n(.*)$/m
52
60
  # escape all html inside this element
53
61
  self.element_content = self.element_content.gsub('<','&lt;').gsub('>','&gt;')
54
62
  # hack to fix <code><nowiki> nested mess
55
63
  self.element_content = self.element_content.gsub(/&lt;[\/]*\s*nowiki\s*&gt;/,'')
56
64
  end
57
65
 
58
- lhandler = @options[:link_handler]
59
66
  case self.element_name
60
- when "math"
61
- blahtex_path = @options[:blahtex_path] || '/usr/bin/blahtex'
62
- blahtex_png_path = @options[:blahtex_png_path] || '/tmp'
63
-
64
- if File.exists?(blahtex_path)
65
- begin
66
- response = `echo '#{self.element_content}' | #{blahtex_path} --png --mathml --png-directory #{blahtex_png_path}`
67
- xml_response = REXML::Document.new(response).root
68
- if @options[:blahtex_html_prefix]
69
- file_md5 = xml_response.elements["png/md5"].text
70
- return "<img src=\"#{File.join(@options[:blahtex_html_prefix],"#{file_md5}.png")}\" />"
71
- else
72
- html = xml_response.elements["mathml/markup"].text
73
- eattr = { "xmlns" => "http://www.w3.org/1998/Math/MathML" }.merge(self.element_attributes)
74
- return elem.tag!(self.element_name, eattr) { |x| x << xml_response.elements["mathml/markup"].children.to_s }
75
- end
76
- rescue => err
77
- return "<span class=\"error\">Unable to parse MathML: #{err}</span>"
78
- end
79
- else
80
- return "<span class=\"error\">blatex binary not found</span>"
81
- end
82
67
  when "template"
68
+ @options[:link_handler].cache({ :name => self.element_attributes["__name"], :content => self.element_content, :md5 => self.element_attributes["__hash"] })
83
69
  return self.element_content
84
70
  when "noinclude"
85
71
  return self.in_template? ? "" : self.element_content
86
72
  when "includeonly"
87
73
  return self.in_template? ? self.element_content : ""
88
- when "ref"
89
- self.element_name = "sup"
90
- named_ref = self.name_attribute
91
- ref = lhandler.find_reference_by_name(named_ref) unless named_ref.nil?
92
- if ref.nil?
93
- lhandler.references << { :name => named_ref, :value => self.element_content, :count => 0 }
94
- ref = lhandler.references.last
95
- end
96
- ref_id = (named_ref.nil? ? "" : "#{named_ref}_") + "#{lhandler.reference_index(ref)}-#{ref[:count]}"
97
- self.params << { :name => "id", :value => "cite_ref-#{ref_id}" }
98
- self.params << { :name => "class", :value => "reference" }
99
- self.element_content = "[<a href=\"#cite_note-" + (named_ref.nil? ? "" : "#{named_ref}_") +
100
- "#{lhandler.reference_index(ref)}\">#{lhandler.reference_index(ref)}</a>]"
101
- ref[:count] += 1
102
- when "references"
103
- ref_count = 0
104
- self.element_name = "ol"
105
- self.element_content = lhandler.references.collect { |r|
106
- ref_count += 1
107
- ref_name = (r[:name].nil? ? "" : r[:name].to_slug + "_")
108
- ret = "<li id=\"cite_note-#{ref_name}#{ref_count}\"><b>"
109
- 1.upto(r[:count]) { |x| ret += "<a href=\"#cite_ref-#{ref_name}#{ref_count}-#{x-1}\">" +
110
- (r[:count] == 1 ? "^" : (x-1).to_s(26).tr('0-9a-p', 'a-z')) + "</a> " }
111
- ret += "</b> #{r[:value]}</li>"
112
- }.to_s
113
74
  when "nowiki"
114
75
  return self.element_content
115
76
  when "a"
@@ -119,6 +80,10 @@ class WikiBuffer::HTMLElement < WikiBuffer
119
80
  # if a element has no href attribute, or href starts with / or ?
120
81
  return elem.tag!(self.element_name, self.element_attributes) { |x| x << self.element_content }
121
82
  end
83
+ else
84
+ if Extension.element_exists?(self.element_name)
85
+ return Extension.html_elements[self.element_name][:klass].new(@options).instance_exec( self, &Extension.html_elements[self.element_name][:block] ).to_s
86
+ end
122
87
  end
123
88
 
124
89
  tmp = elem.tag!(self.element_name, self.element_attributes) { |x| x << self.element_content }
@@ -129,9 +94,9 @@ class WikiBuffer::HTMLElement < WikiBuffer
129
94
  tmp
130
95
  end
131
96
 
132
- def name_attribute
133
- params.each { |p| return p[:value].to_slug if p.kind_of?(Hash) && p[:name] == "name" }
134
- return nil
97
+ def get_attribute_by_name(name)
98
+ params.each { |p| return p[:value] if p.kind_of?(Hash) && p[:name] == name }
99
+ nil
135
100
  end
136
101
 
137
102
  def element_attributes
@@ -267,7 +232,7 @@ class WikiBuffer::HTMLElement < WikiBuffer
267
232
  self.data = "</#{self.data}>"
268
233
  return false
269
234
  else
270
- self.element_content += "&lt;/#{self.data}&gt;"
235
+ self.element_content += skip_html? ? "</#{self.data}>" : "&lt;/#{self.data}&gt;"
271
236
  @start_tag = 0
272
237
  self.data = ""
273
238
  end
@@ -275,9 +240,9 @@ class WikiBuffer::HTMLElement < WikiBuffer
275
240
 
276
241
  else
277
242
  if @start_tag == 0 && ESCAPED_TAGS.include?(self.element_name)
278
- self.data += self.escape_char(current_char)
243
+ self.data << self.escape_char(current_char)
279
244
  else
280
- self.data += current_char
245
+ self.data << current_char
281
246
  end
282
247
  end
283
248
  return true
@@ -12,7 +12,7 @@ class WikiBuffer::Link < WikiBuffer
12
12
  @internal_link ||= false
13
13
  end
14
14
 
15
- def to_s
15
+ def to_html
16
16
  link_handler = @options[:link_handler]
17
17
  unless self.internal_link || params[0].strip !~ /^\s*(([a-z]+):\/\/|[\?\/])/
18
18
  return link_handler.external_link("#{params[0]}".strip, "#{params[1]}".strip)
@@ -22,9 +22,10 @@ class WikiBuffer::Link < WikiBuffer
22
22
  return "[#{params[0]}]"
23
23
  when params[0] =~ /^:(.*)/
24
24
  return link_handler.link_for(params[0],params[1])
25
- when params[0] =~ /^\s*([a-zA-Z0-9-]+)\s*:(.*)$/
25
+ when params[0] =~ /^\s*([^\]\s:]+)\s*:(.*)$/
26
26
  return link_handler.link_for_resource($1,$2,params[1..-1])
27
27
  else
28
+ return "" if params[0].blank? && params[1].blank?
28
29
  return link_handler.link_for(params[0],params[1])
29
30
  end
30
31
  end
@@ -24,7 +24,7 @@ class WikiBuffer::Table < WikiBuffer
24
24
  @rows ||= [ [] ]
25
25
  end
26
26
 
27
- def to_s
27
+ def to_html
28
28
  row_count = 0
29
29
  ret = "<table" + (params[0].blank? ? "" : " #{params[0].strip}") + ">"
30
30
  ret += "<caption" + (self.table_caption_attributes.blank? ? "" : " #{table_caption_attributes.strip}") +
@@ -180,7 +180,7 @@ class WikiBuffer::Table < WikiBuffer
180
180
  @start_row = true
181
181
 
182
182
  else
183
- self.data += current_char
183
+ self.data << current_char
184
184
  end
185
185
 
186
186
  return true
@@ -1,4 +1,5 @@
1
1
  require 'expression_parser'
2
+ require 'digest/md5'
2
3
  require 'uri'
3
4
 
4
5
  module WikiCloth
@@ -24,7 +25,7 @@ class WikiBuffer::Var < WikiBuffer
24
25
  end
25
26
 
26
27
  def skip_links?
27
- true
28
+ false
28
29
  end
29
30
 
30
31
  def skip_html?
@@ -40,18 +41,24 @@ class WikiBuffer::Var < WikiBuffer
40
41
  end
41
42
 
42
43
  def function_name
43
- @fname
44
+ @fname.nil? ? nil : @fname.strip
44
45
  end
45
46
 
46
- def to_s
47
+ def to_html
48
+ return "" if will_not_be_rendered
49
+
47
50
  if self.is_function?
51
+ if Extension.function_exists?(function_name)
52
+ return Extension.functions[function_name][:klass].new(@options).instance_exec( params.collect { |p| p.strip }, &Extension.functions[function_name][:block] ).to_s
53
+ end
48
54
  ret = default_functions(function_name,params.collect { |p| p.strip })
49
55
  ret ||= @options[:link_handler].function(function_name, params.collect { |p| p.strip })
50
56
  ret.to_s
51
57
  elsif self.is_param?
52
58
  ret = nil
53
59
  @options[:buffer].buffers.reverse.each do |b|
54
- ret = b.get_param(params[0].downcase,params[1]) if b.instance_of?(WikiBuffer::HTMLElement) && b.element_name == "template"
60
+ ret = b.get_param(params[0],params[1]) if b.instance_of?(WikiBuffer::HTMLElement) && b.element_name == "template"
61
+ break unless ret.nil?
55
62
  end
56
63
  ret.to_s
57
64
  else
@@ -60,25 +67,46 @@ class WikiBuffer::Var < WikiBuffer
60
67
  b.element_name == "template" }.compact
61
68
  if template_stack.last == params[0]
62
69
  debug_tree = @options[:buffer].buffers.collect { |b| b.debug }.join("-->")
63
- "<span class=\"error\">Template loop detected: &#123;&#123;#{debug_tree}&#125;&#125;</span>"
70
+ "<span class=\"error\">#{I18n.t('template loop detected', :tree => debug_tree)}</span>"
64
71
  else
65
- ret = @options[:link_handler].include_resource("#{params[0]}".strip,params[1..-1]).to_s
72
+ key = params[0].to_s.strip
73
+ key_options = params[1..-1].collect { |p| p.is_a?(Hash) ? { :name => p[:name].strip, :value => p[:value].strip } : p.strip }
74
+ key_options ||= []
75
+ key_digest = Digest::MD5.hexdigest(key_options.to_a.sort {|x,y| (x.is_a?(Hash) ? x[:name] : x) <=> (y.is_a?(Hash) ? y[:name] : y) }.inspect)
76
+
77
+ return @options[:params][key] if @options[:params].has_key?(key)
78
+ # if we have a valid cache fragment use it
79
+ return @options[:cache][key][key_digest] unless @options[:cache].nil? || @options[:cache][key].nil? || @options[:cache][key][key_digest].nil?
80
+
81
+ ret = @options[:link_handler].include_resource(key,key_options).to_s
82
+
66
83
  ret.gsub!(/<!--(.|\s)*?-->/,"")
67
84
  count = 0
68
- tag_attr = self.params[1..-1].collect { |p|
85
+ tag_attr = key_options.collect { |p|
69
86
  if p.instance_of?(Hash)
70
- "#{p[:name].downcase}=\"#{p[:value]}\""
87
+ "#{p[:name]}=\"#{p[:value].gsub(/"/,'&quot;')}\""
71
88
  else
72
89
  count += 1
73
- "#{count}=\"#{p}\""
90
+ "#{count}=\"#{p.gsub(/"/,'&quot;')}\""
74
91
  end
75
92
  }.join(" ")
76
- self.data = ret.blank? ? "" : "<template __name=\"#{params[0]}\" #{tag_attr}>#{ret}</template>"
93
+
94
+ self.data = ret.blank? ? "" : "<template __name=\"#{key}\" __hash=\"#{key_digest}\" #{tag_attr}>#{ret}</template>"
77
95
  ""
78
96
  end
79
97
  end
80
98
  end
81
99
 
100
+ def will_not_be_rendered
101
+ @options[:buffer].buffers.reverse.each do |buffer|
102
+ if buffer.instance_of?(WikiBuffer::Var) && buffer.is_function?
103
+ return true if buffer.function_name == "#if" && buffer.params.size == 2 && buffer.params[0].strip.blank?
104
+ return true if buffer.function_name == "#if" && buffer.params.size == 3 && !buffer.params[0].strip.blank?
105
+ end
106
+ end
107
+ false
108
+ end
109
+
82
110
  def default_functions(name,params)
83
111
  case name
84
112
  when "#if"
@@ -88,12 +116,12 @@ class WikiBuffer::Var < WikiBuffer
88
116
  default = nil
89
117
  for p in params[1..-1]
90
118
  temp = p.split("=")
91
- if temp.length == 1 && p == params.last
119
+ if p !~ /=/ && temp.length == 1 && p == params.last
92
120
  return p
93
- elsif temp.instance_of?(Array) && temp.length > 1
121
+ elsif temp.instance_of?(Array) && temp.length > 0
94
122
  test = temp.first.strip
95
- default = temp[1].strip if test == "#default"
96
- return temp[1].strip if test == match
123
+ default = temp[1..-1].join("=").strip if test == "#default"
124
+ return temp[1..-1].join("=").strip if test == match || (test == "none" && match.blank?)
97
125
  end
98
126
  end
99
127
  default.nil? ? "" : default
@@ -101,7 +129,7 @@ class WikiBuffer::Var < WikiBuffer
101
129
  begin
102
130
  ExpressionParser::Parser.new.parse(params.first)
103
131
  rescue RuntimeError
104
- "Expression error: #{$!}"
132
+ I18n.t('expression error', :error => $!)
105
133
  end
106
134
  when "#ifexpr"
107
135
  val = false
@@ -147,20 +175,40 @@ class WikiBuffer::Var < WikiBuffer
147
175
  when "ucfirst"
148
176
  params.first.capitalize
149
177
  when "lcfirst"
150
- params.first[0,1].downcase + params.first[1,-1]
178
+ params.first[0,1].downcase + params.first[1..-1]
179
+ when "anchorencode"
180
+ params.first.gsub(/\s+/,'_')
151
181
  when "plural"
152
- params.first.to_i > 1 ? params[1] : params[2]
182
+ begin
183
+ expr_value = ExpressionParser::Parser.new.parse(params.first)
184
+ expr_value.to_i == 1 ? params[1] : params[2]
185
+ rescue RuntimeError
186
+ I18n.t('expression error', :error => $!)
187
+ end
153
188
  when "ns"
154
- values = { "" => "", "0" => "", "1" => "Talk", "talk" => "Talk", "2" => "User", "user" => "User",
155
- "3" => "User talk", "user_talk" => "User talk", "4" => "Meta", "project" => "Meta",
156
- "5" => "Meta talk", "project_talk" => "Meta talk", "6" => "File", "image" => "File",
157
- "7" => "File talk", "image_talk" => "File talk", "8" => "MediaWiki", "mediawiki" => "MediaWiki",
158
- "9" => "MediaWiki talk", "mediawiki_talk" => "MediaWiki talk", "10" => "Template",
159
- "template" => "Template", "11" => "Template talk", "template_talk" => "Template talk",
160
- "12" => "Help", "help" => "Help", "13" => "Help talk", "help_talk" => "Help talk",
161
- "14" => "Category", "category" => "Category", "15" => "Category talk", "category_talk" => "Category talk",
162
- "-2" => "Media", "media" => "Media", "-1" => "Special", "special" => "Special" }
163
- values[params.first.gsub(/\s+/,'_').downcase]
189
+ values = {
190
+ "" => "", "0" => "",
191
+ "1" => localise_ns("Talk"), "talk" => localise_ns("Talk"),
192
+ "6" => localise_ns("File"), "file" => localise_ns("File"), "image" => localise_ns("File"),
193
+ "10" => localise_ns("Template"), "template" => localise_ns("Template"),
194
+ "14" => localise_ns("Category"), "category" => localise_ns("Category"),
195
+ "-1" => localise_ns("Special"), "special" => localise_ns("Special"),
196
+ "12" => localise_ns("Help"), "help" => localise_ns("Help"),
197
+ "-2" => localise_ns("Media"), "media" => localise_ns("Media") }
198
+
199
+ values[localise_ns(params.first,:en).gsub(/\s+/,'_').downcase]
200
+ when "#language"
201
+ WikiNamespaces.language_name(params.first)
202
+ when "#tag"
203
+ return "" if params.empty?
204
+ elem = Builder::XmlMarkup.new
205
+ return elem.tag!(params.first) if params.length == 1
206
+ return elem.tag!(params.first) { |e| e << params.last } if params.length == 2
207
+ tag_attrs = {}
208
+ params[1..-2].each do |attr|
209
+ tag_attrs[$1] = $2 if attr =~ /^\s*([\w]+)\s*=\s*"(.*)"\s*$/
210
+ end
211
+ elem.tag!(params.first,tag_attrs) { |e| e << params.last }
164
212
  when "debug"
165
213
  ret = nil
166
214
  case params.first
@@ -183,6 +231,10 @@ class WikiBuffer::Var < WikiBuffer
183
231
  end
184
232
  end
185
233
 
234
+ def localise_ns(name,lang=nil)
235
+ WikiNamespaces.localise_ns(name,lang)
236
+ end
237
+
186
238
  def is_param?
187
239
  @tag_size == 3 ? true : false
188
240
  end
@@ -227,7 +279,7 @@ class WikiBuffer::Var < WikiBuffer
227
279
  end
228
280
 
229
281
  else
230
- self.data += current_char
282
+ self.data << current_char
231
283
  if @tag_start
232
284
  # FIXME: template params and templates colliding
233
285
  if @tag_size > 3
@@ -1,19 +1,12 @@
1
- require 'rubygems'
2
- require 'builder'
3
-
1
+ # encoding: utf-8
4
2
  module WikiCloth
5
3
 
6
- class WikiLinkHandler
4
+ class WikiLinkHandler < WikiNamespaces
7
5
 
8
- FILE_NAMESPACES = ["datei","image","file","media"]
9
- CATEGORY_NAMESPACES = ['kategorie','category']
10
- LANGUAGE_NAMESPACES = ['af','am','ang','ar','arc','ast','az','bn','zh-min-nan','ba','be','be-x-old','bar','bs','br','bg','ca',
11
- 'ceb','cs','co','cy','da','de','dv','et','el','es','eo','eu','fa','fo','fr','fy','ga','gd','gl','gan','ko','hy','hi','hr',
12
- 'io','id','is','it','he','jv','kn','pam','ka','sw','ku','la','lv','lb','lt','hu','mk','mg','ml','mr','arz','ms','nah','nl',
13
- 'ja','no','nn','oc','uz','pap','nds','pl','pt','ksh','ro','qu','ru','sa','sco','sq','scn','simple','sk','sl','sr','sh',
14
- 'fi','sv','tl','ta','th','tg','tr','uk','ur','vi','zh-classical','yi','bat-smg','zh','lo','en','gn','map-bms','pdc','eml',
15
- 'ki','hak','ia','ky','lad','nds-nl','ne','nrm','nov','sm','si','su','kab','te','vec','fiu-vro','wa','war','wuu','zh-yue',
16
- 'diq']
6
+ FILE_NAMESPACES = file_namespace_names
7
+ MEDIA_NAMESPACES = media_namespace_names
8
+ CATEGORY_NAMESPACES = category_namespace_names
9
+ LANGUAGE_NAMESPACES = language_namespace_names
17
10
 
18
11
  def references
19
12
  @references ||= []
@@ -31,6 +24,10 @@ class WikiLinkHandler
31
24
  nil
32
25
  end
33
26
 
27
+ def cache(item)
28
+ nil
29
+ end
30
+
34
31
  def section_list(root=nil)
35
32
  ret = []
36
33
  root = sections[0].children if root.nil?
@@ -44,7 +41,7 @@ class WikiLinkHandler
44
41
  end
45
42
 
46
43
  def toc(sections, toc_numbered=false)
47
- ret = "<table id=\"toc\" class=\"toc\" summary=\"Contents\"><tr><td><div style=\"font-weight:bold\">Table of Contents</div><ul>"
44
+ ret = "<table id=\"toc\" class=\"toc\" summary=\"Contents\"><tr><td><div style=\"font-weight:bold\">#{I18n.t('table of contents')}</div><ul>"
48
45
  previous_depth = 1
49
46
  indices = []
50
47
  section_list(sections).each do |section|
@@ -146,23 +143,19 @@ class WikiLinkHandler
146
143
  end
147
144
 
148
145
  def include_resource(resource, options=[])
149
- if self.params.has_key?(resource)
150
- self.params[resource]
146
+ @template_cache ||= {}
147
+ if @template_cache[resource]
148
+ @included_templates[resource] += 1
149
+ @template_cache[resource]
151
150
  else
152
- @template_cache ||= {}
153
- if @template_cache[resource]
151
+ ret = template(resource)
152
+ unless ret.nil?
153
+ @included_templates ||= {}
154
+ @included_templates[resource] ||= 0
154
155
  @included_templates[resource] += 1
155
- @template_cache[resource]
156
- else
157
- ret = template(resource)
158
- unless ret.nil?
159
- @included_templates ||= {}
160
- @included_templates[resource] ||= 0
161
- @included_templates[resource] += 1
162
- end
163
- @template_cache[resource] = ret
164
- ret
165
156
  end
157
+ @template_cache[resource] = ret
158
+ ret
166
159
  end
167
160
  end
168
161
 
@@ -178,7 +171,7 @@ class WikiLinkHandler
178
171
  ret = ""
179
172
  prefix.downcase!
180
173
  case
181
- when FILE_NAMESPACES.include?(prefix)
174
+ when (MEDIA_NAMESPACES+FILE_NAMESPACES).include?(prefix)
182
175
  ret += wiki_image(resource,options)
183
176
  when CATEGORY_NAMESPACES.include?(prefix)
184
177
  self.categories << resource