| 
									
										
										
										
											2013-12-23 13:05:10 +00:00
										 |  |  | # Redmine - project management software | 
					
						
							| 
									
										
										
										
											2014-01-29 22:45:39 +00:00
										 |  |  | # Copyright (C) 2006-2014  Jean-Philippe Lang | 
					
						
							| 
									
										
										
										
											2013-12-23 13:05:10 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  | # modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  | # as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  | # of the License, or (at your option) any later version. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | # GNU General Public License for more details. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | # along with this program; if not, write to the Free Software | 
					
						
							|  |  |  | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | require 'cgi' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module Redmine | 
					
						
							|  |  |  |   module WikiFormatting | 
					
						
							|  |  |  |     module Markdown | 
					
						
							|  |  |  |       class HTML < Redcarpet::Render::HTML | 
					
						
							|  |  |  |         include ActionView::Helpers::TagHelper | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def link(link, title, content) | 
					
						
							|  |  |  |           css = nil | 
					
						
							|  |  |  |           unless link && link.starts_with?('/') | 
					
						
							|  |  |  |             css = 'external' | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |           content_tag('a', content.html_safe, :href => link, :title => title, :class => css) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def block_code(code, language) | 
					
						
							|  |  |  |           if language.present? | 
					
						
							|  |  |  |             "<pre><code class=\"#{CGI.escapeHTML language} syntaxhl\">" + | 
					
						
							|  |  |  |               Redmine::SyntaxHighlighting.highlight_by_language(code, language) + | 
					
						
							|  |  |  |               "</code></pre>" | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             "<pre>" + CGI.escapeHTML(code) + "</pre>" | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       class Formatter | 
					
						
							|  |  |  |         def initialize(text) | 
					
						
							|  |  |  |           @text = text | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def to_html(*args) | 
					
						
							|  |  |  |           html = formatter.render(@text) | 
					
						
							|  |  |  |           # restore wiki links eg. [[Foo]] | 
					
						
							|  |  |  |           html.gsub!(%r{\[<a href="(.*?)">(.*?)</a>\]}) do | 
					
						
							|  |  |  |             "[[#{$2}]]" | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |           # restore Redmine links with double-quotes, eg. version:"1.0" | 
					
						
							|  |  |  |           html.gsub!(/(\w):"(.+?)"/) do | 
					
						
							|  |  |  |             "#{$1}:\"#{$2}\"" | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |           html | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def get_section(index) | 
					
						
							|  |  |  |           section = extract_sections(index)[1] | 
					
						
							|  |  |  |           hash = Digest::MD5.hexdigest(section) | 
					
						
							|  |  |  |           return section, hash | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def update_section(index, update, hash=nil) | 
					
						
							|  |  |  |           t = extract_sections(index) | 
					
						
							|  |  |  |           if hash.present? && hash != Digest::MD5.hexdigest(t[1]) | 
					
						
							|  |  |  |             raise Redmine::WikiFormatting::StaleSectionError | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |           t[1] = update unless t[1].blank? | 
					
						
							|  |  |  |           t.reject(&:blank?).join "\n\n" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def extract_sections(index) | 
					
						
							|  |  |  |           sections = ['', '', ''] | 
					
						
							|  |  |  |           offset = 0
 | 
					
						
							|  |  |  |           i = 0
 | 
					
						
							|  |  |  |           l = 1
 | 
					
						
							|  |  |  |           inside_pre = false | 
					
						
							|  |  |  |           @text.split(/(^(?:.+\r?\n\r?(?:\=+|\-+)|#+.+|~~~.*)\s*$)/).each do |part| | 
					
						
							|  |  |  |             level = nil | 
					
						
							|  |  |  |             if part =~ /\A~{3,}(\S+)?\s*$/ | 
					
						
							|  |  |  |               if $1 | 
					
						
							|  |  |  |                 if !inside_pre | 
					
						
							|  |  |  |                   inside_pre = true | 
					
						
							|  |  |  |                 end | 
					
						
							|  |  |  |               else | 
					
						
							|  |  |  |                 inside_pre = !inside_pre | 
					
						
							|  |  |  |               end | 
					
						
							|  |  |  |             elsif inside_pre | 
					
						
							|  |  |  |               # nop | 
					
						
							|  |  |  |             elsif part =~ /\A(#+).+/ | 
					
						
							|  |  |  |               level = $1.size | 
					
						
							|  |  |  |             elsif part =~ /\A.+\r?\n\r?(\=+|\-+)\s*$/ | 
					
						
							|  |  |  |               level = $1.include?('=') ? 1 : 2
 | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |             if level | 
					
						
							|  |  |  |               i += 1
 | 
					
						
							|  |  |  |               if offset == 0 && i == index | 
					
						
							|  |  |  |                 # entering the requested section | 
					
						
							|  |  |  |                 offset = 1
 | 
					
						
							|  |  |  |                 l = level | 
					
						
							|  |  |  |               elsif offset == 1 && i > index && level <= l | 
					
						
							|  |  |  |                 # leaving the requested section | 
					
						
							|  |  |  |                 offset = 2
 | 
					
						
							|  |  |  |               end | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |             sections[offset] << part | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |           sections.map(&:strip) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         private | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def formatter | 
					
						
							|  |  |  |           @@formatter ||= Redcarpet::Markdown.new( | 
					
						
							|  |  |  |             Redmine::WikiFormatting::Markdown::HTML.new( | 
					
						
							|  |  |  |               :filter_html => true, | 
					
						
							|  |  |  |               :hard_wrap => true | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             :autolink => true, | 
					
						
							|  |  |  |             :fenced_code_blocks => true, | 
					
						
							|  |  |  |             :space_after_headers => true, | 
					
						
							|  |  |  |             :tables => true, | 
					
						
							|  |  |  |             :strikethrough => true, | 
					
						
							| 
									
										
										
										
											2014-04-26 07:02:45 +00:00
										 |  |  |             :superscript => true, | 
					
						
							|  |  |  |             :no_intra_emphasis => true | 
					
						
							| 
									
										
										
										
											2013-12-23 13:05:10 +00:00
										 |  |  |           ) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |