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
|
||||||
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
|
# Truncates and returns the string as a single line
|
||||||
def truncate_single_line(string, *args)
|
def truncate_single_line(string, *args)
|
||||||
truncate(string, *args).gsub(%r{[\r\n]+}m, ' ')
|
truncate(string, *args).gsub(%r{[\r\n]+}m, ' ')
|
||||||
|
|
|
@ -16,22 +16,6 @@
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
module WikiHelper
|
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)
|
def html_diff(wdiff)
|
||||||
words = wdiff.words.collect{|word| h(word)}
|
words = wdiff.words.collect{|word| h(word)}
|
||||||
|
|
|
@ -43,6 +43,25 @@ class Wiki < ActiveRecord::Base
|
||||||
page
|
page
|
||||||
end
|
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
|
# turn a string into a valid page title
|
||||||
def self.titleize(title)
|
def self.titleize(title)
|
||||||
# replace spaces with _ and remove unwanted caracters
|
# replace spaces with _ and remove unwanted caracters
|
||||||
|
|
|
@ -23,6 +23,15 @@ module Redmine
|
||||||
method_name = "macro_#{name}"
|
method_name = "macro_#{name}"
|
||||||
send(method_name, obj, args) if respond_to?(method_name)
|
send(method_name, obj, args) if respond_to?(method_name)
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
@@available_macros = {}
|
@@available_macros = {}
|
||||||
|
@ -77,24 +86,29 @@ module Redmine
|
||||||
content_tag('dl', out)
|
content_tag('dl', out)
|
||||||
end
|
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|
|
macro :child_pages do |obj, args|
|
||||||
raise 'This macro applies to wiki pages only.' unless obj.is_a?(WikiContent)
|
args, options = extract_macro_options(args, :parent)
|
||||||
render_page_hierarchy(obj.page.descendants.group_by(&:parent_id), obj.page.id)
|
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
|
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)}}"
|
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|
|
macro :include do |obj, args|
|
||||||
project = @project
|
page = Wiki.find_page(args.first.to_s, :project => @project)
|
||||||
title = args.first.to_s
|
raise 'Page not found' if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project)
|
||||||
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
|
|
||||||
@included_wiki_pages ||= []
|
@included_wiki_pages ||= []
|
||||||
raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title)
|
raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title)
|
||||||
@included_wiki_pages << page.title
|
@included_wiki_pages << page.title
|
||||||
|
|
|
@ -47,4 +47,26 @@ wiki_contents_004:
|
||||||
version: 1
|
version: 1
|
||||||
author_id: 1
|
author_id: 1
|
||||||
comments:
|
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
|
wiki_id: 1
|
||||||
protected: false
|
protected: false
|
||||||
parent_id: 1
|
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+}, '')
|
assert_equal expected.gsub(%r{\s+}, ''), textilizable(raw).gsub(%r{\s+}, '')
|
||||||
end
|
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
|
def test_default_formatter
|
||||||
Setting.text_formatting = 'unknown'
|
Setting.text_formatting = 'unknown'
|
||||||
text = 'a *link*: http://www.example.net/'
|
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