1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
require 'awesome_nested_set/move'
module CollectiveIdea #:nodoc:
module Acts #:nodoc:
module NestedSet #:nodoc:
module Model
module Movable
def move_possible?(target)
self != target && # Can't target self
same_scope?(target) && # can't be in different scopes
# detect impossible move
within_bounds?(target.left, target.left) &&
within_bounds?(target.right, target.right)
end
# Shorthand method for finding the left sibling and moving to the left of it.
def move_left
move_to_left_of left_sibling
end
# Shorthand method for finding the right sibling and moving to the right of it.
def move_right
move_to_right_of right_sibling
end
# Move the node to the left of another node
def move_to_left_of(node)
move_to node, :left
end
# Move the node to the right of another node
def move_to_right_of(node)
move_to node, :right
end
# Move the node to the child of another node
def move_to_child_of(node)
if node == :root
move_to_root
else
move_to node, :child
end
end
# Move the node to the child of another node with specify index
def move_to_child_with_index(node, index)
siblings = node == :root ? roots : node.children
if siblings.empty?
move_to_child_of(node)
elsif siblings.count == index
move_to_right_of(siblings.last)
else
my_position = siblings.index(self)
if my_position && my_position < index
# e.g. if self is at position 0 and we want to move self to position 1 then self
# needs to move to the *right* of the node at position 1. That's because the node
# that is currently at position 1 will be at position 0 after the move completes.
move_to_right_of(siblings[index])
elsif my_position && my_position == index
# do nothing. already there.
else
move_to_left_of(siblings[index])
end
end
end
# Move the node to root nodes
def move_to_root
move_to self, :root
end
# Order children in a nested set by an attribute
# Can order by any attribute class that uses the Comparable mixin, for example a string or integer
# Usage example when sorting categories alphabetically: @new_category.move_to_ordered_child_of(@root, "name")
def move_to_ordered_child_of(parent, order_attribute, ascending = true)
self.move_to_root and return unless parent
left_neighbor = find_left_neighbor(parent, order_attribute, ascending)
self.move_to_child_of(parent)
return unless parent.children.many?
if left_neighbor
self.move_to_right_of(left_neighbor)
else # Self is the left most node.
self.move_to_left_of(parent.children[0])
end
end
# Find the node immediately to the left of this node.
def find_left_neighbor(parent, order_attribute, ascending)
left = nil
parent.children.each do |n|
if ascending
left = n if n.send(order_attribute) < self.send(order_attribute)
else
left = n if n.send(order_attribute) > self.send(order_attribute)
end
end
left
end
def move_to(target, position)
prevent_unpersisted_move
run_callbacks :move do
in_tenacious_transaction do
target = reload_target(target, position)
self.reload_nested_set
Move.new(target, position, self).move
update_counter_cache
end
after_move_to(target, position)
end
end
protected
def after_move_to(target, position)
target.reload_nested_set if target
self.set_depth_for_self_and_descendants!
self.reload_nested_set
end
def move_to_new_parent
if @move_to_new_parent_id.nil?
move_to_root
elsif @move_to_new_parent_id
move_to_child_of(@move_to_new_parent_id)
end
end
def out_of_bounds?(left_bound, right_bound)
left <= left_bound && right >= right_bound
end
def prevent_unpersisted_move
if self.new_record?
raise ActiveRecord::ActiveRecordError, "You cannot move a new node"
end
end
def within_bounds?(left_bound, right_bound)
!out_of_bounds?(left_bound, right_bound)
end
end
end
end
end
end
|