Extends child_pages macro to display child pages based on page parameter (#1975).
It can also be called from anywhere now (not only from wiki pages). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2053 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
af7e586b06
commit
06266c8fec
|
@ -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, ' ')
|
||||
|
|
|
@ -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)}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
@ -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
|
||||
|
|
@ -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/'
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue