render_404 unless @annotate
end
- # remove a wiki page and its history
+ # Removes a wiki page and its history
+ # Children can be either set as root pages, removed or reassigned to another parent page
def destroy
return render_403 unless editable?
+
+ @descendants_count = @page.descendants.size
+ if @descendants_count > 0
+ case params[:todo]
+ when 'nullify'
+ # Nothing to do
+ when 'destroy'
+ # Removes all its descendants
+ @page.descendants.each(&:destroy)
+ when 'reassign'
+ # Reassign children to another parent page
+ reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i)
+ return unless reassign_to
+ @page.children.each do |child|
+ child.update_attribute(:parent, reassign_to)
+ end
+ else
+ @reassignable_to = @wiki.pages - @page.self_and_descendants
+ return
+ end
+ end
@page.destroy
redirect_to :action => 'special', :id => @project, :page => 'Page_index'
end
module WikiHelper
+ def wiki_page_options_for_select(pages, selected = nil, parent = nil, level = 0)
+ s = ''
+ pages.select {|p| p.parent == parent}.each do |page|
+ attrs = "value='#{page.id}'"
+ attrs << " selected='selected'" if selected == page
+ indent = (level > 0) ? (' ' * level * 2 + '» ') : nil
+
+ s << "<option value='#{page.id}'>#{indent}#{h page.pretty_title}</option>\n" +
+ wiki_page_options_for_select(pages, selected, page, level + 1)
+ end
+ s
+ end
+
def html_diff(wdiff)
words = wdiff.words.collect{|word| h(word)}
words_add = 0
belongs_to :wiki
has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy
acts_as_attachable :delete_permission => :delete_wiki_pages_attachments
- acts_as_tree :order => 'title'
+ acts_as_tree :dependent => :nullify, :order => 'title'
acts_as_event :title => Proc.new {|o| "#{l(:label_wiki)}: #{o.title}"},
:description => :text,
--- /dev/null
+<h2><%=h @page.pretty_title %></h2>
+
+<% form_tag({}) do %>
+<div class="box">
+<p><strong><%= l(:text_wiki_page_destroy_question, :descendants => @descendants_count) %></strong></p>
+<p><label><%= radio_button_tag 'todo', 'nullify', true %> <%= l(:text_wiki_page_nullify_children) %></label><br />
+<label><%= radio_button_tag 'todo', 'destroy', false %> <%= l(:text_wiki_page_destroy_children) %></label>
+<% if @reassignable_to.any? %>
+<br />
+<label><%= radio_button_tag 'todo', 'reassign', false %> <%= l(:text_wiki_page_reassign_children) %></label>:
+<%= select_tag 'reassign_to_id', wiki_page_options_for_select(@reassignable_to),
+ :onclick => "$('todo_reassign').checked = true;" %>
+<% end %>
+</p>
+</div>
+
+<%= submit_tag l(:button_apply) %>
+<%= link_to l(:button_cancel), :controller => 'wiki', :action => 'index', :id => @project, :page => @page.title %>
+<% end %>
-<h2><%= @page.pretty_title %></h2>
+<h2><%=h @page.pretty_title %></h2>
<% form_for :content, @content, :url => {:action => 'edit', :page => @page.title}, :html => {:id => 'wiki_form'} do |f| %>
<%= f.hidden_field :version %>
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_descending: Opadajuće
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?\r
+ text_wiki_page_reassign_children: Reassign child pages to this parent page\r
+ text_wiki_page_nullify_children: Keep child pages as root pages\r
+ text_wiki_page_destroy_children: Delete child pages and all their descendants\r
enumeration_activities: Activitats (seguidor de temps)
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: Od {{start}} do {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
text_repository_usernames_mapping: "Select or update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped."
text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.'
text_custom_field_possible_values_info: 'One line for each value'
+ text_wiki_page_destroy_question: "This page has {{descendants}} child page(s) and descendant(s). What do you want to do?"
+ text_wiki_page_nullify_children: "Keep child pages as root pages"
+ text_wiki_page_destroy_children: "Delete child pages and all their descendants"
+ text_wiki_page_reassign_children: "Reassign child pages to this parent page"
default_role_manager: Manager
default_role_developper: Developer
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
text_repository_usernames_mapping: "Vous pouvez sélectionner ou modifier l'utilisateur Redmine associé à chaque nom d'utilisateur figurant dans l'historique du dépôt.\nLes utilisateurs avec le même identifiant ou la même adresse mail seront automatiquement associés."
text_diff_truncated: '... Ce différentiel a été tronqué car il excède la taille maximale pouvant être affichée.'
text_custom_field_possible_values_info: 'Une ligne par valeur'
+ text_wiki_page_destroy_question: "Cette page possède {{descendants}} sous-page(s) et descendante(s). Que voulez-vous faire ?"
+ text_wiki_page_nullify_children: "Conserver les sous-pages en tant que pages racines"
+ text_wiki_page_destroy_children: "Supprimer les sous-pages et toutes leurs descedantes"
+ text_wiki_page_reassign_children: "Réaffecter les sous-pages à cette page"
default_role_manager: Manager
default_role_developper: Développeur
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: "{{start}} -tól {{end}} -ig"
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: Van {{start}} tot {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: Od {{start}} do {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: De {{start}} até {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
enumeration_activities: Activitati (timp de lucru)
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
text_workflow_edit: Выберите роль и трекер для редактирования последовательности состояний
warning_attachments_not_saved: "{{count}} файл(ов) невозможно сохранить."
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: Od {{start}} do {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
enumeration_issue_priorities: Ärendeprioriteter
enumeration_doc_categories: Dokumentkategorier
enumeration_activities: Aktiviteter (tidsuppföljning)
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
enumeration_issue_priorities: 項目優先權
enumeration_doc_categories: 文件分類
enumeration_activities: 活動 (時間追蹤)
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
enumeration_issue_priorities: 问题优先级
enumeration_doc_categories: 文档类别
enumeration_activities: 活动(时间跟踪)
+ text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
+ text_wiki_page_reassign_children: Reassign child pages to this parent page
+ text_wiki_page_nullify_children: Keep child pages as root pages
+ text_wiki_page_destroy_children: Delete child pages and all their descendants
)
end
- def test_destroy
+ def test_destroy_child
@request.session[:user_id] = 2
- post :destroy, :id => 1, :page => 'CookBook_documentation'
+ post :destroy, :id => 1, :page => 'Child_1'
assert_redirected_to :action => 'special', :id => 'ecookbook', :page => 'Page_index'
end
+ def test_destroy_parent
+ @request.session[:user_id] = 2
+ assert_no_difference('WikiPage.count') do
+ post :destroy, :id => 1, :page => 'Another_page'
+ end
+ assert_response :success
+ assert_template 'destroy'
+ end
+
+ def test_destroy_parent_with_nullify
+ @request.session[:user_id] = 2
+ assert_difference('WikiPage.count', -1) do
+ post :destroy, :id => 1, :page => 'Another_page', :todo => 'nullify'
+ end
+ assert_redirected_to :action => 'special', :id => 'ecookbook', :page => 'Page_index'
+ assert_nil WikiPage.find_by_id(2)
+ end
+
+ def test_destroy_parent_with_cascade
+ @request.session[:user_id] = 2
+ assert_difference('WikiPage.count', -3) do
+ post :destroy, :id => 1, :page => 'Another_page', :todo => 'destroy'
+ end
+ assert_redirected_to :action => 'special', :id => 'ecookbook', :page => 'Page_index'
+ assert_nil WikiPage.find_by_id(2)
+ assert_nil WikiPage.find_by_id(5)
+ end
+
+ def test_destroy_parent_with_reassign
+ @request.session[:user_id] = 2
+ assert_difference('WikiPage.count', -1) do
+ post :destroy, :id => 1, :page => 'Another_page', :todo => 'reassign', :reassign_to_id => 1
+ end
+ assert_redirected_to :action => 'special', :id => 'ecookbook', :page => 'Page_index'
+ assert_nil WikiPage.find_by_id(2)
+ assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent
+ end
+
def test_special_routing
assert_routing(
{:method => :get, :path => '/projects/567/wiki/page_index'},
assert WikiContent.find_all_by_page_id(1).empty?
assert WikiContent.versioned_class.find_all_by_page_id(1).empty?
end
+
+ def test_destroy_should_not_nullify_children
+ page = WikiPage.find(2)
+ child_ids = page.child_ids
+ assert child_ids.any?
+ page.destroy
+ assert_nil WikiPage.find_by_id(2)
+
+ children = WikiPage.find_all_by_id(child_ids)
+ assert_equal child_ids.size, children.size
+ children.each do |child|
+ assert_nil child.parent_id
+ end
+ end
end
# * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet.
# * <tt>counter_cache</tt> - keeps a count in a +children_count+ column if set to +true+ (default: +false+).
def acts_as_tree(options = {})
- configuration = { :foreign_key => "parent_id", :order => nil, :counter_cache => nil }
+ configuration = { :foreign_key => "parent_id", :dependent => :destroy, :order => nil, :counter_cache => nil }
configuration.update(options) if options.is_a?(Hash)
belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache]
- has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => :destroy
+ has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => configuration[:dependent]
class_eval <<-EOV
include ActiveRecord::Acts::Tree::InstanceMethods
children + children.collect(&:children).flatten
end
+ # Returns list of descendants and a reference to the current node.
+ #
+ # root.self_and_descendants # => [root, child1, subchild1, subchild2]
+ def self_and_descendants
+ [self] + descendants
+ end
+
# Returns the root node of the tree.
def root
node = self