##// END OF EJS Templates
Extends child_pages macro to display child pages based on page parameter (#1975)....
Jean-Philippe Lang -
r2051:06266c8fecd7
parent child
Show More
@@ -0,0 +1,98
1 # Redmine - project management software
2 # Copyright (C) 2006-2008 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 require File.dirname(__FILE__) + '/../../../../test_helper'
19
20 class Redmine::WikiFormatting::MacrosTest < HelperTestCase
21 include ApplicationHelper
22 include ActionView::Helpers::TextHelper
23 fixtures :projects, :roles, :enabled_modules, :users,
24 :repositories, :changesets,
25 :trackers, :issue_statuses, :issues,
26 :versions, :documents,
27 :wikis, :wiki_pages, :wiki_contents,
28 :boards, :messages,
29 :attachments
30
31 def setup
32 super
33 @project = nil
34 end
35
36 def teardown
37 end
38
39 def test_macro_hello_world
40 text = "{{hello_world}}"
41 assert textilizable(text).match(/Hello world!/)
42 # escaping
43 text = "!{{hello_world}}"
44 assert_equal '<p>{{hello_world}}</p>', textilizable(text)
45 end
46
47 def test_macro_include
48 @project = Project.find(1)
49 # include a page of the current project wiki
50 text = "{{include(Another page)}}"
51 assert textilizable(text).match(/This is a link to a ticket/)
52
53 @project = nil
54 # include a page of a specific project wiki
55 text = "{{include(ecookbook:Another page)}}"
56 assert textilizable(text).match(/This is a link to a ticket/)
57
58 text = "{{include(ecookbook:)}}"
59 assert textilizable(text).match(/CookBook documentation/)
60
61 text = "{{include(unknowidentifier:somepage)}}"
62 assert textilizable(text).match(/Page not found/)
63 end
64
65 def test_macro_child_pages
66 expected = "<p><ul class=\"pages-hierarchy\">\n" +
67 "<li><a href=\"/wiki/ecookbook/Child_1\">Child 1</a></li>\n" +
68 "<li><a href=\"/wiki/ecookbook/Child_2\">Child 2</a></li>\n" +
69 "</ul>\n</p>"
70
71 @project = Project.find(1)
72 # child pages of the current wiki page
73 assert_equal expected, textilizable("{{child_pages}}", :object => WikiPage.find(2).content)
74 # child pages of another page
75 assert_equal expected, textilizable("{{child_pages(Another_page)}}", :object => WikiPage.find(1).content)
76
77 @project = Project.find(2)
78 assert_equal expected, textilizable("{{child_pages(ecookbook:Another_page)}}", :object => WikiPage.find(1).content)
79 end
80
81 def test_macro_child_pages_with_option
82 expected = "<p><ul class=\"pages-hierarchy\">\n" +
83 "<li><a href=\"/wiki/ecookbook/Another_page\">Another page</a>\n" +
84 "<ul class=\"pages-hierarchy\">\n" +
85 "<li><a href=\"/wiki/ecookbook/Child_1\">Child 1</a></li>\n" +
86 "<li><a href=\"/wiki/ecookbook/Child_2\">Child 2</a></li>\n" +
87 "</ul>\n</li>\n</ul>\n</p>"
88
89 @project = Project.find(1)
90 # child pages of the current wiki page
91 assert_equal expected, textilizable("{{child_pages(parent=1)}}", :object => WikiPage.find(2).content)
92 # child pages of another page
93 assert_equal expected, textilizable("{{child_pages(Another_page, parent=1)}}", :object => WikiPage.find(1).content)
94
95 @project = Project.find(2)
96 assert_equal expected, textilizable("{{child_pages(ecookbook:Another_page, parent=1)}}", :object => WikiPage.find(1).content)
97 end
98 end
@@ -119,6 +119,22 module ApplicationHelper
119 end
119 end
120 end
120 end
121
121
122 def render_page_hierarchy(pages, node=nil)
123 content = ''
124 if pages[node]
125 content << "<ul class=\"pages-hierarchy\">\n"
126 pages[node].each do |page|
127 content << "<li>"
128 content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'index', :id => page.project, :page => page.title},
129 :title => (page.respond_to?(:updated_on) ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
130 content << "\n" + render_page_hierarchy(pages, page.id) if pages[page.id]
131 content << "</li>\n"
132 end
133 content << "</ul>\n"
134 end
135 content
136 end
137
122 # Truncates and returns the string as a single line
138 # Truncates and returns the string as a single line
123 def truncate_single_line(string, *args)
139 def truncate_single_line(string, *args)
124 truncate(string, *args).gsub(%r{[\r\n]+}m, ' ')
140 truncate(string, *args).gsub(%r{[\r\n]+}m, ' ')
@@ -16,22 +16,6
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 module WikiHelper
18 module WikiHelper
19
20 def render_page_hierarchy(pages, node=nil)
21 content = ''
22 if pages[node]
23 content << "<ul class=\"pages-hierarchy\">\n"
24 pages[node].each do |page|
25 content << "<li>"
26 content << link_to(h(page.pretty_title), {:action => 'index', :page => page.title},
27 :title => (page.respond_to?(:updated_on) ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
28 content << "\n" + render_page_hierarchy(pages, page.id) if pages[page.id]
29 content << "</li>\n"
30 end
31 content << "</ul>\n"
32 end
33 content
34 end
35
19
36 def html_diff(wdiff)
20 def html_diff(wdiff)
37 words = wdiff.words.collect{|word| h(word)}
21 words = wdiff.words.collect{|word| h(word)}
@@ -43,6 +43,25 class Wiki < ActiveRecord::Base
43 page
43 page
44 end
44 end
45
45
46 # Finds a page by title
47 # The given string can be of one of the forms: "title" or "project:title"
48 # Examples:
49 # Wiki.find_page("bar", project => foo)
50 # Wiki.find_page("foo:bar")
51 def self.find_page(title, options = {})
52 project = options[:project]
53 if title.to_s =~ %r{^([^\:]+)\:(.*)$}
54 project_identifier, title = $1, $2
55 project = Project.find_by_identifier(project_identifier) || Project.find_by_name(project_identifier)
56 end
57 if project && project.wiki
58 page = project.wiki.find_page(title)
59 if page && page.content
60 page
61 end
62 end
63 end
64
46 # turn a string into a valid page title
65 # turn a string into a valid page title
47 def self.titleize(title)
66 def self.titleize(title)
48 # replace spaces with _ and remove unwanted caracters
67 # replace spaces with _ and remove unwanted caracters
@@ -23,6 +23,15 module Redmine
23 method_name = "macro_#{name}"
23 method_name = "macro_#{name}"
24 send(method_name, obj, args) if respond_to?(method_name)
24 send(method_name, obj, args) if respond_to?(method_name)
25 end
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
26 end
35 end
27
36
28 @@available_macros = {}
37 @@available_macros = {}
@@ -77,24 +86,29 module Redmine
77 content_tag('dl', out)
86 content_tag('dl', out)
78 end
87 end
79
88
80 desc "Displays a list of child pages."
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"
81 macro :child_pages do |obj, args|
93 macro :child_pages do |obj, args|
82 raise 'This macro applies to wiki pages only.' unless obj.is_a?(WikiContent)
94 args, options = extract_macro_options(args, :parent)
83 render_page_hierarchy(obj.page.descendants.group_by(&:parent_id), obj.page.id)
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)
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)
84 end
106 end
85
107
86 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)}}"
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)}}"
87 macro :include do |obj, args|
109 macro :include do |obj, args|
88 project = @project
110 page = Wiki.find_page(args.first.to_s, :project => @project)
89 title = args.first.to_s
111 raise 'Page not found' if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project)
90 if title =~ %r{^([^\:]+)\:(.*)$}
91 project_identifier, title = $1, $2
92 project = Project.find_by_identifier(project_identifier) || Project.find_by_name(project_identifier)
93 end
94 raise 'Unknow project' unless project && User.current.allowed_to?(:view_wiki_pages, project)
95 raise 'No wiki for this project' unless !project.wiki.nil?
96 page = project.wiki.find_page(title)
97 raise "Page #{args.first} doesn't exist" unless page && page.content
98 @included_wiki_pages ||= []
112 @included_wiki_pages ||= []
99 raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title)
113 raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title)
100 @included_wiki_pages << page.title
114 @included_wiki_pages << page.title
@@ -47,4 +47,26 wiki_contents_004:
47 page_id: 4
47 page_id: 4
48 id: 4
48 id: 4
49 version: 1
49 version: 1
50 author_id: 1
51 comments:
52 wiki_contents_005:
53 text: |-
54 h1. Child page 1
55
56 This is a child page
57 updated_on: 2007-03-08 00:18:07 +01:00
58 page_id: 5
59 id: 5
60 version: 1
61 author_id: 1
62 comments:
63 wiki_contents_006:
64 text: |-
65 h1. Child page 2
66
67 This is a child page
68 updated_on: 2007-03-08 00:18:07 +01:00
69 page_id: 6
70 id: 6
71 version: 1
50 author_id: 1 No newline at end of file
72 author_id: 1
@@ -27,4 +27,18 wiki_pages_004:
27 wiki_id: 1
27 wiki_id: 1
28 protected: false
28 protected: false
29 parent_id: 1
29 parent_id: 1
30 wiki_pages_005:
31 created_on: 2007-03-08 00:18:07 +01:00
32 title: Child_1
33 id: 5
34 wiki_id: 1
35 protected: false
36 parent_id: 2
37 wiki_pages_006:
38 created_on: 2007-03-08 00:18:07 +01:00
39 title: Child_2
40 id: 6
41 wiki_id: 1
42 protected: false
43 parent_id: 2
30 No newline at end of file
44
@@ -359,32 +359,6 EXPECTED
359 assert_equal expected.gsub(%r{\s+}, ''), textilizable(raw).gsub(%r{\s+}, '')
359 assert_equal expected.gsub(%r{\s+}, ''), textilizable(raw).gsub(%r{\s+}, '')
360 end
360 end
361
361
362 def test_macro_hello_world
363 text = "{{hello_world}}"
364 assert textilizable(text).match(/Hello world!/)
365 # escaping
366 text = "!{{hello_world}}"
367 assert_equal '<p>{{hello_world}}</p>', textilizable(text)
368 end
369
370 def test_macro_include
371 @project = Project.find(1)
372 # include a page of the current project wiki
373 text = "{{include(Another page)}}"
374 assert textilizable(text).match(/This is a link to a ticket/)
375
376 @project = nil
377 # include a page of a specific project wiki
378 text = "{{include(ecookbook:Another page)}}"
379 assert textilizable(text).match(/This is a link to a ticket/)
380
381 text = "{{include(ecookbook:)}}"
382 assert textilizable(text).match(/CookBook documentation/)
383
384 text = "{{include(unknowidentifier:somepage)}}"
385 assert textilizable(text).match(/Unknow project/)
386 end
387
388 def test_default_formatter
362 def test_default_formatter
389 Setting.text_formatting = 'unknown'
363 Setting.text_formatting = 'unknown'
390 text = 'a *link*: http://www.example.net/'
364 text = 'a *link*: http://www.example.net/'
General Comments 0
You need to be logged in to leave comments. Login now