To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / lib / redmine / wiki_formatting / macros.rb @ 441:cbce1fd3b1b7
History | View | Annotate | Download (4.83 KB)
| 1 |
# redMine - project management software
|
|---|---|
| 2 |
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
| 3 |
#
|
| 4 |
# This program is free software; you can redistribute it and/or
|
| 5 |
# modify it under the terms of the GNU General Public License
|
| 6 |
# as published by the Free Software Foundation; either version 2
|
| 7 |
# of the License, or (at your option) any later version.
|
| 8 |
#
|
| 9 |
# This program is distributed in the hope that it will be useful,
|
| 10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 12 |
# GNU General Public License for more details.
|
| 13 |
#
|
| 14 |
# You should have received a copy of the GNU General Public License
|
| 15 |
# along with this program; if not, write to the Free Software
|
| 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
| 17 |
|
| 18 |
module Redmine |
| 19 |
module WikiFormatting |
| 20 |
module Macros |
| 21 |
module Definitions |
| 22 |
def exec_macro(name, obj, args) |
| 23 |
method_name = "macro_#{name}"
|
| 24 |
send(method_name, obj, args) if respond_to?(method_name)
|
| 25 |
end
|
| 26 |
|
| 27 |
def extract_macro_options(args, *keys) |
| 28 |
options = {}
|
| 29 |
while args.last.to_s.strip =~ %r{^(.+)\=(.+)$} && keys.include?($1.downcase.to_sym) |
| 30 |
options[$1.downcase.to_sym] = $2 |
| 31 |
args.pop |
| 32 |
end
|
| 33 |
return [args, options]
|
| 34 |
end
|
| 35 |
end
|
| 36 |
|
| 37 |
@@available_macros = {}
|
| 38 |
|
| 39 |
class << self |
| 40 |
# Called with a block to define additional macros.
|
| 41 |
# Macro blocks accept 2 arguments:
|
| 42 |
# * obj: the object that is rendered
|
| 43 |
# * args: macro arguments
|
| 44 |
#
|
| 45 |
# Plugins can use this method to define new macros:
|
| 46 |
#
|
| 47 |
# Redmine::WikiFormatting::Macros.register do
|
| 48 |
# desc "This is my macro"
|
| 49 |
# macro :my_macro do |obj, args|
|
| 50 |
# "My macro output"
|
| 51 |
# end
|
| 52 |
# end
|
| 53 |
def register(&block) |
| 54 |
class_eval(&block) if block_given?
|
| 55 |
end
|
| 56 |
|
| 57 |
private |
| 58 |
# Defines a new macro with the given name and block.
|
| 59 |
def macro(name, &block) |
| 60 |
name = name.to_sym if name.is_a?(String) |
| 61 |
@@available_macros[name] = @@desc || '' |
| 62 |
@@desc = nil |
| 63 |
raise "Can not create a macro without a block!" unless block_given? |
| 64 |
Definitions.send :define_method, "macro_#{name}".downcase, &block |
| 65 |
end
|
| 66 |
|
| 67 |
# Sets description for the next macro to be defined
|
| 68 |
def desc(txt) |
| 69 |
@@desc = txt
|
| 70 |
end
|
| 71 |
end
|
| 72 |
|
| 73 |
# Builtin macros
|
| 74 |
desc "Sample macro."
|
| 75 |
macro :hello_world do |obj, args| |
| 76 |
"Hello world! Object: #{obj.class.name}, " + (args.empty? ? "Called with no argument." : "Arguments: #{args.join(', ')}") |
| 77 |
end
|
| 78 |
|
| 79 |
desc "Displays a list of all available macros, including description if available."
|
| 80 |
macro :macro_list do |
| 81 |
out = ''
|
| 82 |
@@available_macros.keys.collect(&:to_s).sort.each do |macro| |
| 83 |
out << content_tag('dt', content_tag('code', macro)) |
| 84 |
out << content_tag('dd', textilizable(@@available_macros[macro.to_sym])) |
| 85 |
end
|
| 86 |
content_tag('dl', out)
|
| 87 |
end
|
| 88 |
|
| 89 |
desc "Displays a list of child pages. With no argument, it displays the child pages of the current wiki page. Examples:\n\n" +
|
| 90 |
" !{{child_pages}} -- can be used from a wiki page only\n" +
|
| 91 |
" !{{child_pages(Foo)}} -- lists all children of page Foo\n" +
|
| 92 |
" !{{child_pages(Foo, parent=1)}} -- same as above with a link to page Foo"
|
| 93 |
macro :child_pages do |obj, args| |
| 94 |
args, options = extract_macro_options(args, :parent)
|
| 95 |
page = nil
|
| 96 |
if args.size > 0 |
| 97 |
page = Wiki.find_page(args.first.to_s, :project => @project) |
| 98 |
elsif obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version) |
| 99 |
page = obj.page |
| 100 |
else
|
| 101 |
raise 'With no argument, this macro can be called from wiki pages only.'
|
| 102 |
end
|
| 103 |
raise 'Page not found' if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project) |
| 104 |
pages = ([page] + page.descendants).group_by(&:parent_id)
|
| 105 |
render_page_hierarchy(pages, options[:parent] ? page.parent_id : page.id)
|
| 106 |
end
|
| 107 |
|
| 108 |
desc "Include a wiki page. Example:\n\n !{{include(Foo)}}\n\nor to include a page of a specific project wiki:\n\n !{{include(projectname:Foo)}}"
|
| 109 |
macro :include do |obj, args| |
| 110 |
page = Wiki.find_page(args.first.to_s, :project => @project) |
| 111 |
raise 'Page not found' if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project) |
| 112 |
@included_wiki_pages ||= []
|
| 113 |
raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title) |
| 114 |
@included_wiki_pages << page.title
|
| 115 |
out = textilizable(page.content, :text, :attachments => page.attachments, :headings => false) |
| 116 |
@included_wiki_pages.pop
|
| 117 |
out |
| 118 |
end
|
| 119 |
end
|
| 120 |
end
|
| 121 |
end
|