summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/helpers/application_helper.rb16
-rw-r--r--app/helpers/wiki_helper.rb16
-rw-r--r--app/models/wiki.rb19
-rw-r--r--lib/redmine/wiki_formatting/macros.rb40
-rw-r--r--test/fixtures/wiki_contents.yml22
-rw-r--r--test/fixtures/wiki_pages.yml14
-rw-r--r--test/unit/helpers/application_helper_test.rb26
-rw-r--r--test/unit/lib/redmine/wiki_formatting/macros_test.rb98
8 files changed, 196 insertions, 55 deletions
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 4a72b022b..248704609 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -119,6 +119,22 @@ module ApplicationHelper
end
end
+ def render_page_hierarchy(pages, node=nil)
+ content = ''
+ if pages[node]
+ content << "<ul class=\"pages-hierarchy\">\n"
+ pages[node].each do |page|
+ content << "<li>"
+ content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'index', :id => page.project, :page => page.title},
+ :title => (page.respond_to?(:updated_on) ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
+ content << "\n" + render_page_hierarchy(pages, page.id) if pages[page.id]
+ content << "</li>\n"
+ end
+ content << "</ul>\n"
+ end
+ content
+ end
+
# Truncates and returns the string as a single line
def truncate_single_line(string, *args)
truncate(string, *args).gsub(%r{[\r\n]+}m, ' ')
diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb
index 0a6b810de..c692c748b 100644
--- a/app/helpers/wiki_helper.rb
+++ b/app/helpers/wiki_helper.rb
@@ -16,22 +16,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module WikiHelper
-
- def render_page_hierarchy(pages, node=nil)
- content = ''
- if pages[node]
- content << "<ul class=\"pages-hierarchy\">\n"
- pages[node].each do |page|
- content << "<li>"
- content << link_to(h(page.pretty_title), {:action => 'index', :page => page.title},
- :title => (page.respond_to?(:updated_on) ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
- content << "\n" + render_page_hierarchy(pages, page.id) if pages[page.id]
- content << "</li>\n"
- end
- content << "</ul>\n"
- end
- content
- end
def html_diff(wdiff)
words = wdiff.words.collect{|word| h(word)}
diff --git a/app/models/wiki.rb b/app/models/wiki.rb
index 3432a2bc7..be048775a 100644
--- a/app/models/wiki.rb
+++ b/app/models/wiki.rb
@@ -43,6 +43,25 @@ class Wiki < ActiveRecord::Base
page
end
+ # Finds a page by title
+ # The given string can be of one of the forms: "title" or "project:title"
+ # Examples:
+ # Wiki.find_page("bar", project => foo)
+ # Wiki.find_page("foo:bar")
+ def self.find_page(title, options = {})
+ project = options[:project]
+ if title.to_s =~ %r{^([^\:]+)\:(.*)$}
+ project_identifier, title = $1, $2
+ project = Project.find_by_identifier(project_identifier) || Project.find_by_name(project_identifier)
+ end
+ if project && project.wiki
+ page = project.wiki.find_page(title)
+ if page && page.content
+ page
+ end
+ end
+ end
+
# turn a string into a valid page title
def self.titleize(title)
# replace spaces with _ and remove unwanted caracters
diff --git a/lib/redmine/wiki_formatting/macros.rb b/lib/redmine/wiki_formatting/macros.rb
index adfc590e4..abc07b947 100644
--- a/lib/redmine/wiki_formatting/macros.rb
+++ b/lib/redmine/wiki_formatting/macros.rb
@@ -23,6 +23,15 @@ module Redmine
method_name = "macro_#{name}"
send(method_name, obj, args) if respond_to?(method_name)
end
+
+ def extract_macro_options(args, *keys)
+ options = {}
+ while args.last.to_s.strip =~ %r{^(.+)\=(.+)$} && keys.include?($1.downcase.to_sym)
+ options[$1.downcase.to_sym] = $2
+ args.pop
+ end
+ return [args, options]
+ end
end
@@available_macros = {}
@@ -77,24 +86,29 @@ module Redmine
content_tag('dl', out)
end
- desc "Displays a list of child pages."
+ desc "Displays a list of child pages. With no argument, it displays the child pages of the current wiki page. Examples:\n\n" +
+ " !{{child_pages}} -- can be used from a wiki page only\n" +
+ " !{{child_pages(Foo)}} -- lists all children of page Foo\n" +
+ " !{{child_pages(Foo, parent=1)}} -- same as above with a link to page Foo"
macro :child_pages do |obj, args|
- raise 'This macro applies to wiki pages only.' unless obj.is_a?(WikiContent)
- render_page_hierarchy(obj.page.descendants.group_by(&:parent_id), obj.page.id)
+ args, options = extract_macro_options(args, :parent)
+ page = nil
+ if args.size > 0
+ page = Wiki.find_page(args.first.to_s, :project => @project)
+ elsif obj.is_a?(WikiContent)
+ page = obj.page
+ else
+ raise 'With no argument, this macro can be called from wiki pages only.'
+ end
+ raise 'Page not found' if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project)
+ pages = ([page] + page.descendants).group_by(&:parent_id)
+ render_page_hierarchy(pages, options[:parent] ? page.parent_id : page.id)
end
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)}}"
macro :include do |obj, args|
- project = @project
- title = args.first.to_s
- if title =~ %r{^([^\:]+)\:(.*)$}
- project_identifier, title = $1, $2
- project = Project.find_by_identifier(project_identifier) || Project.find_by_name(project_identifier)
- end
- raise 'Unknow project' unless project && User.current.allowed_to?(:view_wiki_pages, project)
- raise 'No wiki for this project' unless !project.wiki.nil?
- page = project.wiki.find_page(title)
- raise "Page #{args.first} doesn't exist" unless page && page.content
+ page = Wiki.find_page(args.first.to_s, :project => @project)
+ raise 'Page not found' if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project)
@included_wiki_pages ||= []
raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title)
@included_wiki_pages << page.title
diff --git a/test/fixtures/wiki_contents.yml b/test/fixtures/wiki_contents.yml
index 8c53d4d97..8798ff229 100644
--- a/test/fixtures/wiki_contents.yml
+++ b/test/fixtures/wiki_contents.yml
@@ -47,4 +47,26 @@ wiki_contents_004:
version: 1
author_id: 1
comments:
+wiki_contents_005:
+ text: |-
+ h1. Child page 1
+
+ This is a child page
+ updated_on: 2007-03-08 00:18:07 +01:00
+ page_id: 5
+ id: 5
+ version: 1
+ author_id: 1
+ comments:
+wiki_contents_006:
+ text: |-
+ h1. Child page 2
+
+ This is a child page
+ updated_on: 2007-03-08 00:18:07 +01:00
+ page_id: 6
+ id: 6
+ version: 1
+ author_id: 1
+ comments:
\ No newline at end of file
diff --git a/test/fixtures/wiki_pages.yml b/test/fixtures/wiki_pages.yml
index e285441ff..8d29c2f72 100644
--- a/test/fixtures/wiki_pages.yml
+++ b/test/fixtures/wiki_pages.yml
@@ -27,4 +27,18 @@ wiki_pages_004:
wiki_id: 1
protected: false
parent_id: 1
+wiki_pages_005:
+ created_on: 2007-03-08 00:18:07 +01:00
+ title: Child_1
+ id: 5
+ wiki_id: 1
+ protected: false
+ parent_id: 2
+wiki_pages_006:
+ created_on: 2007-03-08 00:18:07 +01:00
+ title: Child_2
+ id: 6
+ wiki_id: 1
+ protected: false
+ parent_id: 2
\ No newline at end of file
diff --git a/test/unit/helpers/application_helper_test.rb b/test/unit/helpers/application_helper_test.rb
index d23300309..31bc1e49d 100644
--- a/test/unit/helpers/application_helper_test.rb
+++ b/test/unit/helpers/application_helper_test.rb
@@ -359,32 +359,6 @@ EXPECTED
assert_equal expected.gsub(%r{\s+}, ''), textilizable(raw).gsub(%r{\s+}, '')
end
- def test_macro_hello_world
- text = "{{hello_world}}"
- assert textilizable(text).match(/Hello world!/)
- # escaping
- text = "!{{hello_world}}"
- assert_equal '<p>{{hello_world}}</p>', textilizable(text)
- end
-
- def test_macro_include
- @project = Project.find(1)
- # include a page of the current project wiki
- text = "{{include(Another page)}}"
- assert textilizable(text).match(/This is a link to a ticket/)
-
- @project = nil
- # include a page of a specific project wiki
- text = "{{include(ecookbook:Another page)}}"
- assert textilizable(text).match(/This is a link to a ticket/)
-
- text = "{{include(ecookbook:)}}"
- assert textilizable(text).match(/CookBook documentation/)
-
- text = "{{include(unknowidentifier:somepage)}}"
- assert textilizable(text).match(/Unknow project/)
- end
-
def test_default_formatter
Setting.text_formatting = 'unknown'
text = 'a *link*: http://www.example.net/'
diff --git a/test/unit/lib/redmine/wiki_formatting/macros_test.rb b/test/unit/lib/redmine/wiki_formatting/macros_test.rb
new file mode 100644
index 000000000..b5284acd3
--- /dev/null
+++ b/test/unit/lib/redmine/wiki_formatting/macros_test.rb
@@ -0,0 +1,98 @@
+# Redmine - project management software
+# Copyright (C) 2006-2008 Jean-Philippe Lang
+#
+# 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 File.dirname(__FILE__) + '/../../../../test_helper'
+
+class Redmine::WikiFormatting::MacrosTest < HelperTestCase
+ include ApplicationHelper
+ include ActionView::Helpers::TextHelper
+ fixtures :projects, :roles, :enabled_modules, :users,
+ :repositories, :changesets,
+ :trackers, :issue_statuses, :issues,
+ :versions, :documents,
+ :wikis, :wiki_pages, :wiki_contents,
+ :boards, :messages,
+ :attachments
+
+ def setup
+ super
+ @project = nil
+ end
+
+ def teardown
+ end
+
+ def test_macro_hello_world
+ text = "{{hello_world}}"
+ assert textilizable(text).match(/Hello world!/)
+ # escaping
+ text = "!{{hello_world}}"
+ assert_equal '<p>{{hello_world}}</p>', textilizable(text)
+ end
+
+ def test_macro_include
+ @project = Project.find(1)
+ # include a page of the current project wiki
+ text = "{{include(Another page)}}"
+ assert textilizable(text).match(/This is a link to a ticket/)
+
+ @project = nil
+ # include a page of a specific project wiki
+ text = "{{include(ecookbook:Another page)}}"
+ assert textilizable(text).match(/This is a link to a ticket/)
+
+ text = "{{include(ecookbook:)}}"
+ assert textilizable(text).match(/CookBook documentation/)
+
+ text = "{{include(unknowidentifier:somepage)}}"
+ assert textilizable(text).match(/Page not found/)
+ end
+
+ def test_macro_child_pages
+ expected = "<p><ul class=\"pages-hierarchy\">\n" +
+ "<li><a href=\"/wiki/ecookbook/Child_1\">Child 1</a></li>\n" +
+ "<li><a href=\"/wiki/ecookbook/Child_2\">Child 2</a></li>\n" +
+ "</ul>\n</p>"
+
+ @project = Project.find(1)
+ # child pages of the current wiki page
+ assert_equal expected, textilizable("{{child_pages}}", :object => WikiPage.find(2).content)
+ # child pages of another page
+ assert_equal expected, textilizable("{{child_pages(Another_page)}}", :object => WikiPage.find(1).content)
+
+ @project = Project.find(2)
+ assert_equal expected, textilizable("{{child_pages(ecookbook:Another_page)}}", :object => WikiPage.find(1).content)
+ end
+
+ def test_macro_child_pages_with_option
+ expected = "<p><ul class=\"pages-hierarchy\">\n" +
+ "<li><a href=\"/wiki/ecookbook/Another_page\">Another page</a>\n" +
+ "<ul class=\"pages-hierarchy\">\n" +
+ "<li><a href=\"/wiki/ecookbook/Child_1\">Child 1</a></li>\n" +
+ "<li><a href=\"/wiki/ecookbook/Child_2\">Child 2</a></li>\n" +
+ "</ul>\n</li>\n</ul>\n</p>"
+
+ @project = Project.find(1)
+ # child pages of the current wiki page
+ assert_equal expected, textilizable("{{child_pages(parent=1)}}", :object => WikiPage.find(2).content)
+ # child pages of another page
+ assert_equal expected, textilizable("{{child_pages(Another_page, parent=1)}}", :object => WikiPage.find(1).content)
+
+ @project = Project.find(2)
+ assert_equal expected, textilizable("{{child_pages(ecookbook:Another_page, parent=1)}}", :object => WikiPage.find(1).content)
+ end
+end