diff -urN redmine-1.3.0/app/helpers/application_helper.rb redmine-1.3.0_macros_escaping/app/helpers/application_helper.rb --- redmine-1.3.0/app/helpers/application_helper.rb 2011-12-10 16:53:33.000000000 +0200 +++ redmine-1.3.0_macros_escaping/app/helpers/application_helper.rb 2011-12-27 00:21:55.751959515 +0200 @@ -19,6 +19,7 @@ require 'forwardable' require 'cgi' +require 'digest/md5' module ApplicationHelper include Redmine::WikiFormatting::Macros::Definitions @@ -487,6 +488,8 @@ project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) only_path = options.delete(:only_path) == false ? false : true + text, macros_grabbed = preprocess_macros(text) + options[:macros_grabbed] = macros_grabbed text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) @parsed_headings = [] @@ -497,6 +500,10 @@ end end + # Any macros not parsed by this point must be in
blocks - and, hence, should be + # restored to their original state. + restore_macros(text, macros_grabbed) unless text.nil? + if @parsed_headings.any? replace_toc(text, @parsed_headings) end @@ -788,16 +795,35 @@ ( \{\{ # opening tag ([\w]+) # macro name - (\(([^\}]*)\))? # optional arguments + (\((.*?)\))? # optional arguments \}\} # closing tag - ) - /x unless const_defined?(:MACROS_RE) + ) + /xm unless const_defined?(:MACROS_RE) + + def preprocess_macros(text) + macros_grabbed = {} + text = text.gsub(MACROS_RE) do |s| + esc, all, macro = $1, $2, $3.downcase + if esc.nil? and (WikiExternalFilterHelper.has_macro macro rescue false) + args = $5 + key = Digest::MD5.hexdigest("#{macro}:#{args}") + macros_grabbed[key] = {:macro => macro, :args => args, :raw => s} + "{{_macros_grabbed(#{key})}}" + else + s + end + end + [text, macros_grabbed] + end # Macros substitution def parse_macros(text, project, obj, attr, only_path, options) text.gsub!(MACROS_RE) do esc, all, macro = $1, $2, $3.downcase args = ($5 || '').split(',').each(&:strip) + if macro == '_macros_grabbed' and options[:macros_grabbed].member? args.first + macro, args = options[:macros_grabbed][args.first].values_at(:macro, :args) + end if esc.nil? begin exec_macro(macro, obj, args) @@ -807,6 +833,18 @@ else all end + end + end + + # Macros restoration to their original state - used forblocks. + def restore_macros(text, macros_grabbed) + text.gsub!(MACROS_RE) do + all, macro, args = $&, $3.downcase, $5 + if macro == '_macros_grabbed' and macros_grabbed.member? args + "#{macros_grabbed[args].values_at(:raw)}" + else + all + end end end