| 
									
										
										
										
											2019-03-17 16:36:34 +00:00
										 |  |  | # frozen_string_literal: true | 
					
						
							| 
									
										
										
										
											2019-03-15 01:32:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-10-27 11:08:29 +00:00
										 |  |  | # Redmine - project management software | 
					
						
							| 
									
										
										
										
											2020-03-03 00:24:10 +00:00
										 |  |  | # Copyright (C) 2006-2020  Jean-Philippe Lang | 
					
						
							| 
									
										
										
										
											2008-10-27 11:08:29 +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. | 
					
						
							| 
									
										
										
										
											2011-09-01 02:04:13 +00:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2008-10-27 11:08:29 +00:00
										 |  |  | # 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. | 
					
						
							| 
									
										
										
										
											2011-09-01 02:04:13 +00:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2008-10-27 11:08:29 +00:00
										 |  |  | # 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. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-03 17:16:53 +00:00
										 |  |  | require File.expand_path('../redcloth3', __FILE__) | 
					
						
							| 
									
										
										
										
											2011-11-18 16:25:00 +00:00
										 |  |  | require 'digest/md5' | 
					
						
							| 
									
										
										
										
											2008-10-27 11:08:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | module Redmine | 
					
						
							|  |  |  |   module WikiFormatting | 
					
						
							|  |  |  |     module Textile | 
					
						
							|  |  |  |       class Formatter < RedCloth3 | 
					
						
							| 
									
										
										
										
											2010-03-24 20:26:22 +00:00
										 |  |  |         include ActionView::Helpers::TagHelper | 
					
						
							| 
									
										
										
										
											2012-03-04 10:04:46 +00:00
										 |  |  |         include Redmine::WikiFormatting::LinksHelper | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         alias :inline_auto_link :auto_link! | 
					
						
							|  |  |  |         alias :inline_auto_mailto :auto_mailto! | 
					
						
							| 
									
										
										
										
											2018-06-17 05:45:17 +00:00
										 |  |  |         alias :inline_restore_redmine_links :restore_redmine_links | 
					
						
							| 
									
										
										
										
											2011-09-01 02:04:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-10-27 11:08:29 +00:00
										 |  |  |         # auto_link rule after textile rules so that it doesn't break !image_url! tags | 
					
						
							| 
									
										
										
										
											2018-06-17 05:45:17 +00:00
										 |  |  |         RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto, :inline_restore_redmine_links] | 
					
						
							| 
									
										
										
										
											2011-09-01 02:04:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-10-27 11:08:29 +00:00
										 |  |  |         def initialize(*args) | 
					
						
							|  |  |  |           super | 
					
						
							|  |  |  |           self.hard_breaks=true | 
					
						
							|  |  |  |           self.no_span_caps=true | 
					
						
							| 
									
										
										
										
											2012-02-12 14:00:43 +00:00
										 |  |  |           self.filter_styles=false | 
					
						
							| 
									
										
										
										
											2008-10-27 11:08:29 +00:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-09-01 02:04:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-06 10:40:21 +00:00
										 |  |  |         def to_html(*rules) | 
					
						
							| 
									
										
										
										
											2008-10-27 11:08:29 +00:00
										 |  |  |           @toc = [] | 
					
						
							|  |  |  |           super(*RULES).to_s | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-09-01 02:04:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-18 16:25:00 +00:00
										 |  |  |         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) | 
					
						
							|  |  |  |           @pre_list = [] | 
					
						
							|  |  |  |           text = self.dup | 
					
						
							| 
									
										
										
										
											2011-11-28 22:08:15 +00:00
										 |  |  |           rip_offtags text, false, false | 
					
						
							| 
									
										
										
										
											2019-03-17 16:36:34 +00:00
										 |  |  |           before = +'' | 
					
						
							|  |  |  |           s = +'' | 
					
						
							|  |  |  |           after = +'' | 
					
						
							| 
									
										
										
										
											2011-11-18 16:25:00 +00:00
										 |  |  |           i = 0
 | 
					
						
							|  |  |  |           l = 1
 | 
					
						
							|  |  |  |           started = false | 
					
						
							|  |  |  |           ended = false | 
					
						
							| 
									
										
										
										
											2013-01-10 22:05:22 +00:00
										 |  |  |           text.scan(/(((?:.*?)(\A|\r?\n\s*\r?\n))(h(\d+)(#{A}#{C})\.(?::(\S+))?[ \t](.*?)$)|.*)/m).each do |all, content, lf, heading, level| | 
					
						
							| 
									
										
										
										
											2011-11-18 16:25:00 +00:00
										 |  |  |             if heading.nil? | 
					
						
							|  |  |  |               if ended | 
					
						
							|  |  |  |                 after << all | 
					
						
							|  |  |  |               elsif started | 
					
						
							|  |  |  |                 s << all | 
					
						
							|  |  |  |               else | 
					
						
							|  |  |  |                 before << all | 
					
						
							|  |  |  |               end | 
					
						
							|  |  |  |               break | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |             i += 1
 | 
					
						
							|  |  |  |             if ended | 
					
						
							|  |  |  |               after << all | 
					
						
							|  |  |  |             elsif i == index | 
					
						
							|  |  |  |               l = level.to_i | 
					
						
							|  |  |  |               before << content | 
					
						
							|  |  |  |               s << heading | 
					
						
							|  |  |  |               started = true | 
					
						
							|  |  |  |             elsif i > index | 
					
						
							|  |  |  |               s << content | 
					
						
							|  |  |  |               if level.to_i > l | 
					
						
							|  |  |  |                 s << heading | 
					
						
							|  |  |  |               else | 
					
						
							|  |  |  |                 after << heading | 
					
						
							|  |  |  |                 ended = true | 
					
						
							|  |  |  |               end | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |               before << all | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |           sections = [before.strip, s.strip, after.strip] | 
					
						
							| 
									
										
										
										
											2011-11-28 21:45:02 +00:00
										 |  |  |           sections.each {|section| smooth_offtags_without_code_highlighting section} | 
					
						
							| 
									
										
										
										
											2011-11-18 16:25:00 +00:00
										 |  |  |           sections | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-15 17:25:42 +00:00
										 |  |  |         private | 
					
						
							| 
									
										
										
										
											2011-09-01 02:04:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-10-27 11:08:29 +00:00
										 |  |  |         # Patch for RedCloth.  Fixed in RedCloth r128 but _why hasn't released it yet. | 
					
						
							|  |  |  |         # <a href="http://code.whytheluckystiff.net/redcloth/changeset/128">http://code.whytheluckystiff.net/redcloth/changeset/128</a> | 
					
						
							| 
									
										
										
										
											2011-09-01 02:04:13 +00:00
										 |  |  |         def hard_break( text ) | 
					
						
							| 
									
										
										
										
											2011-03-14 20:35:36 +00:00
										 |  |  |           text.gsub!( /(.)\n(?!\n|\Z| *([#*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks | 
					
						
							| 
									
										
										
										
											2008-10-27 11:08:29 +00:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-09-01 02:04:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-28 21:45:02 +00:00
										 |  |  |         alias :smooth_offtags_without_code_highlighting :smooth_offtags | 
					
						
							| 
									
										
										
										
											2008-10-27 11:08:29 +00:00
										 |  |  |         # Patch to add code highlighting support to RedCloth | 
					
						
							|  |  |  |         def smooth_offtags( text ) | 
					
						
							|  |  |  |           unless @pre_list.empty? | 
					
						
							|  |  |  |             ## replace <pre> content | 
					
						
							|  |  |  |             text.gsub!(/<redpre#(\d+)>/) do | 
					
						
							|  |  |  |               content = @pre_list[$1.to_i] | 
					
						
							| 
									
										
										
										
											2019-12-05 11:25:24 +00:00
										 |  |  |               # This regex must match any data produced by RedCloth3#rip_offtags | 
					
						
							|  |  |  |               if content.match(/<code\s+class=(?:"([^"]+)"|'([^']+)')>\s?(.*)/m) | 
					
						
							|  |  |  |                 language = $1 || $2 | 
					
						
							|  |  |  |                 text = $3 | 
					
						
							| 
									
										
										
										
											2017-04-06 16:41:52 +00:00
										 |  |  |                 if Redmine::SyntaxHighlighting.language_supported?(language) | 
					
						
							| 
									
										
										
										
											2018-09-29 06:57:40 +00:00
										 |  |  |                   text.gsub!(/x%x%/, '&') | 
					
						
							| 
									
										
										
										
											2017-04-06 16:41:52 +00:00
										 |  |  |                   content = "<code class=\"#{language} syntaxhl\">" + | 
					
						
							|  |  |  |                     Redmine::SyntaxHighlighting.highlight_by_language(text, language) | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                   content = "<code>#{ERB::Util.h(text)}" | 
					
						
							|  |  |  |                 end | 
					
						
							| 
									
										
										
										
											2008-10-27 11:08:29 +00:00
										 |  |  |               end | 
					
						
							|  |  |  |               content | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |