gitlab-org--gitlab-foss/app/models/concerns/relative_positioning.rb

135 lines
3 KiB
Ruby
Raw Normal View History

2017-02-01 13:41:01 -05:00
module RelativePositioning
extend ActiveSupport::Concern
MIN_POSITION = 0
MAX_POSITION = Gitlab::Database::MAX_INT_VALUE
2017-02-01 13:41:01 -05:00
included do
after_save :save_positionable_neighbours
end
def min_relative_position
self.class.in_projects(project.id).minimum(:relative_position)
2017-02-01 13:41:01 -05:00
end
def max_relative_position
self.class.in_projects(project.id).maximum(:relative_position)
2017-02-01 13:41:01 -05:00
end
def prev_relative_position
prev_pos = nil
if self.relative_position
prev_pos = self.class.
in_projects(project.id).
2017-02-01 13:41:01 -05:00
where('relative_position < ?', self.relative_position).
maximum(:relative_position)
end
prev_pos || MIN_POSITION
end
def next_relative_position
next_pos = nil
if self.relative_position
next_pos = self.class.
in_projects(project.id).
2017-02-01 13:41:01 -05:00
where('relative_position > ?', self.relative_position).
minimum(:relative_position)
end
next_pos || MAX_POSITION
end
def move_between(before, after)
return move_after(before) if before && !after
return move_before(after) if after && !before
pos_before = before.relative_position
pos_after = after.relative_position
if pos_before && pos_after
if pos_before == pos_after
2017-03-02 11:09:48 -05:00
self.relative_position = pos_before
2017-02-01 13:41:01 -05:00
before.move_before(self)
after.move_after(self)
2017-03-02 11:09:48 -05:00
2017-02-01 13:41:01 -05:00
@positionable_neighbours = [before, after]
else
self.relative_position = position_between(pos_before, pos_after)
end
elsif pos_before
self.move_after(before)
after.move_after(self)
2017-03-02 11:09:48 -05:00
2017-02-01 13:41:01 -05:00
@positionable_neighbours = [after]
elsif pos_after
self.move_before(after)
before.move_before(self)
2017-03-02 11:09:48 -05:00
2017-02-01 13:41:01 -05:00
@positionable_neighbours = [before]
else
move_to_end
before.move_before(self)
after.move_after(self)
2017-03-02 11:09:48 -05:00
2017-02-01 13:41:01 -05:00
@positionable_neighbours = [before, after]
end
end
def move_before(after)
pos_after = after.relative_position
2017-03-02 11:09:48 -05:00
2017-02-01 13:41:01 -05:00
if pos_after
self.relative_position = position_between(MIN_POSITION, pos_after)
2017-02-01 13:41:01 -05:00
else
move_to_end
after.move_after(self)
2017-03-02 11:09:48 -05:00
2017-02-01 13:41:01 -05:00
@positionable_neighbours = [after]
end
end
def move_after(before)
pos_before = before.relative_position
2017-03-02 11:09:48 -05:00
2017-02-01 13:41:01 -05:00
if pos_before
self.relative_position = position_between(pos_before, MAX_POSITION)
2017-02-01 13:41:01 -05:00
else
move_to_end
before.move_before(self)
2017-03-02 11:09:48 -05:00
2017-02-01 13:41:01 -05:00
@positionable_neighbours = [before]
end
end
def move_to_end
2017-03-02 11:09:48 -05:00
self.relative_position = position_between(max_relative_position, MAX_POSITION)
2017-02-01 13:41:01 -05:00
end
def move_between!(*args)
move_between(*args) && save!
end
private
def position_between(pos_before, pos_after)
2017-03-02 11:09:48 -05:00
pos_before ||= MIN_POSITION
pos_after ||= MAX_POSITION
2017-02-01 13:41:01 -05:00
pos_before, pos_after = [pos_before, pos_after].sort
rand(pos_before.next..pos_after.pred)
2017-02-01 13:41:01 -05:00
end
def save_positionable_neighbours
return unless @positionable_neighbours
2017-03-02 11:09:48 -05:00
status = @positionable_neighbours.all?(&:save)
2017-02-01 13:41:01 -05:00
@positionable_neighbours = nil
2017-03-02 11:09:48 -05:00
status
2017-02-01 13:41:01 -05:00
end
end