19 |
19 |
|
20 |
20 |
require 'forwardable'
|
21 |
21 |
require 'cgi'
|
|
22 |
require 'digest/md5'
|
22 |
23 |
|
23 |
24 |
module ApplicationHelper
|
24 |
25 |
include Redmine::WikiFormatting::Macros::Definitions
|
... | ... | |
487 |
488 |
project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
|
488 |
489 |
only_path = options.delete(:only_path) == false ? false : true
|
489 |
490 |
|
|
491 |
text, macros_grabbed = preprocess_macros(text)
|
|
492 |
options[:macros_grabbed] = macros_grabbed
|
490 |
493 |
text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr)
|
491 |
494 |
|
492 |
495 |
@parsed_headings = []
|
... | ... | |
497 |
500 |
end
|
498 |
501 |
end
|
499 |
502 |
|
|
503 |
# Any macros not parsed by this point must be in <pre> blocks - and, hence, should be
|
|
504 |
# restored to their original state.
|
|
505 |
restore_macros(text, macros_grabbed) unless text.nil?
|
|
506 |
|
500 |
507 |
if @parsed_headings.any?
|
501 |
508 |
replace_toc(text, @parsed_headings)
|
502 |
509 |
end
|
... | ... | |
788 |
795 |
(
|
789 |
796 |
\{\{ # opening tag
|
790 |
797 |
([\w]+) # macro name
|
791 |
|
(\(([^\}]*)\))? # optional arguments
|
|
798 |
(\((.*?)\))? # optional arguments
|
792 |
799 |
\}\} # closing tag
|
793 |
|
)
|
794 |
|
/x unless const_defined?(:MACROS_RE)
|
|
800 |
)
|
|
801 |
/xm unless const_defined?(:MACROS_RE)
|
|
802 |
|
|
803 |
def preprocess_macros(text)
|
|
804 |
macros_grabbed = {}
|
|
805 |
text = text.gsub(MACROS_RE) do |s|
|
|
806 |
esc, all, macro = $1, $2, $3.downcase
|
|
807 |
if esc.nil? and (WikiExternalFilterHelper.has_macro macro rescue false)
|
|
808 |
args = $5
|
|
809 |
key = Digest::MD5.hexdigest("#{macro}:#{args}")
|
|
810 |
macros_grabbed[key] = {:macro => macro, :args => args, :raw => s}
|
|
811 |
"{{_macros_grabbed(#{key})}}"
|
|
812 |
else
|
|
813 |
s
|
|
814 |
end
|
|
815 |
end
|
|
816 |
[text, macros_grabbed]
|
|
817 |
end
|
795 |
818 |
|
796 |
819 |
# Macros substitution
|
797 |
820 |
def parse_macros(text, project, obj, attr, only_path, options)
|
798 |
821 |
text.gsub!(MACROS_RE) do
|
799 |
822 |
esc, all, macro = $1, $2, $3.downcase
|
800 |
823 |
args = ($5 || '').split(',').each(&:strip)
|
|
824 |
if macro == '_macros_grabbed' and options[:macros_grabbed].member? args.first
|
|
825 |
macro, args = options[:macros_grabbed][args.first].values_at(:macro, :args)
|
|
826 |
end
|
801 |
827 |
if esc.nil?
|
802 |
828 |
begin
|
803 |
829 |
exec_macro(macro, obj, args)
|
... | ... | |
807 |
833 |
else
|
808 |
834 |
all
|
809 |
835 |
end
|
|
836 |
end
|
|
837 |
end
|
|
838 |
|
|
839 |
# Macros restoration to their original state - used for <pre> blocks.
|
|
840 |
def restore_macros(text, macros_grabbed)
|
|
841 |
text.gsub!(MACROS_RE) do
|
|
842 |
all, macro, args = $&, $3.downcase, $5
|
|
843 |
if macro == '_macros_grabbed' and macros_grabbed.member? args
|
|
844 |
"#{macros_grabbed[args].values_at(:raw)}"
|
|
845 |
else
|
|
846 |
all
|
|
847 |
end
|
810 |
848 |
end
|
811 |
849 |
end
|
812 |
850 |
|