forked from saurabh/orbit4-5
Member Profile Custom Fields, Member Status Complete, Member Position Reordering
This commit is contained in:
parent
41cdabb5d3
commit
ce9d1f327f
|
@ -6,7 +6,7 @@ function dragMode() {
|
||||||
_userPosition.position = $(ui.item).index();
|
_userPosition.position = $(ui.item).index();
|
||||||
_userPosition.id = $(ui.item).data('user-id');
|
_userPosition.id = $(ui.item).data('user-id');
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "<%#= Rails.application.routes.url_helpers.update_order_card_admin_users_new_interface_index_path %>",
|
url: "<%= Rails.application.routes.url_helpers.update_order_card_admin_members_path %>",
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
dataType: 'script',
|
dataType: 'script',
|
||||||
data: {users: _userPosition}
|
data: {users: _userPosition}
|
||||||
|
@ -46,7 +46,7 @@ function typeMode() {
|
||||||
_userPosition.push([$(this).val(), $(this).siblings('a').data('user-id')]);
|
_userPosition.push([$(this).val(), $(this).siblings('a').data('user-id')]);
|
||||||
});
|
});
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "<%#= Rails.application.routes.url_helpers.update_order_list_admin_users_new_interface_index_path %>",
|
url: "<%= Rails.application.routes.url_helpers.update_order_list_admin_members_path %>",
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
dataType: 'script',
|
dataType: 'script',
|
||||||
data: {users: _userPosition}
|
data: {users: _userPosition}
|
||||||
|
|
|
@ -2,7 +2,7 @@ class Admin::MembersController < OrbitMemberController
|
||||||
before_action :set_member_profile, only: [:show, :edit, :update]
|
before_action :set_member_profile, only: [:show, :edit, :update]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@roles = Role.where(disabled: false).asc("_id")
|
@roles = Role.excludes(disabled: true)
|
||||||
page_num = params[:page] || 1
|
page_num = params[:page] || 1
|
||||||
|
|
||||||
@filter = params[:filter]
|
@filter = params[:filter]
|
||||||
|
@ -70,6 +70,7 @@ class Admin::MembersController < OrbitMemberController
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
@custom_fields = @member.member_profile_field_values rescue nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
|
@ -91,10 +92,17 @@ class Admin::MembersController < OrbitMemberController
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@member = MemberProfile.new(member_profile_params)
|
@member = MemberProfile.new(member_profile_params)
|
||||||
@user = User.new(user_params)
|
@user = User.new(user_params) rescue nil
|
||||||
|
|
||||||
if @member.save
|
if @member.save
|
||||||
@user.member_profile_id = @member.id
|
@user.member_profile_id = @member.id
|
||||||
|
|
||||||
|
if !params[:member_profile_field_value].nil?
|
||||||
|
params[:member_profile_field_value].each_with_index do |m,i|
|
||||||
|
@custom_field_value = @member.member_profile_field_values.new(value: m.second["value"], member_profile_field_id: m.second["member_profile_field_id"])
|
||||||
|
@custom_field_value.save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@user.save
|
@user.save
|
||||||
redirect_to admin_members_path
|
redirect_to admin_members_path
|
||||||
else
|
else
|
||||||
|
@ -131,7 +139,9 @@ class Admin::MembersController < OrbitMemberController
|
||||||
@member_profile.delete
|
@member_profile.delete
|
||||||
end
|
end
|
||||||
|
|
||||||
render action: "index"
|
respond_to do |format|
|
||||||
|
format.js
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def unapproved_members
|
def unapproved_members
|
||||||
|
@ -173,6 +183,70 @@ class Admin::MembersController < OrbitMemberController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def edit_order_card
|
||||||
|
@members = MemberProfile.order('created_at DESC')
|
||||||
|
@type = 'card'
|
||||||
|
render 'edit_order'
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit_order_list
|
||||||
|
@members = MemberProfile.order('created_at DESC')
|
||||||
|
@type = 'list'
|
||||||
|
render 'edit_order'
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_order_card
|
||||||
|
@error = false
|
||||||
|
if params[:users].present?
|
||||||
|
to_go = params[:users][:position].to_i
|
||||||
|
member_at_position = MemberProfile.find_by(position: to_go + 1)
|
||||||
|
member = MemberProfile.find(params[:users][:id])
|
||||||
|
if member_at_position
|
||||||
|
if member.position > member_at_position.position
|
||||||
|
member.move_above(member_at_position)
|
||||||
|
else
|
||||||
|
member.move_below(member_at_position)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
render nothing: true, status: 200
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_order_list
|
||||||
|
@error = []
|
||||||
|
if params[:users].present?
|
||||||
|
params[:users].values.sort.each do |pair|
|
||||||
|
to_go = pair[0].to_i
|
||||||
|
|
||||||
|
if to_go > 0
|
||||||
|
member_at_position = MemberProfile.where(position: to_go).first
|
||||||
|
member = MemberProfile.find(pair[1])
|
||||||
|
if member_at_position && !(member_at_position == member)
|
||||||
|
if member.position > member_at_position.position
|
||||||
|
member.move_above(member_at_position)
|
||||||
|
else
|
||||||
|
member.move_below(member_at_position)
|
||||||
|
end
|
||||||
|
elsif to_go > MemberProfile.count
|
||||||
|
member.move_to_bottom
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@members = MemberProfile.asc(:position)
|
||||||
|
end
|
||||||
|
|
||||||
|
def setting_account
|
||||||
|
if params[:member_id].blank?
|
||||||
|
redirect_to action: :index
|
||||||
|
else
|
||||||
|
@user = MemberProfile.find(params[:member_id])
|
||||||
|
if current_user.id != @user.id
|
||||||
|
redirect_to action: :index
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Use callbacks to share common setup or constraints between actions.
|
# Use callbacks to share common setup or constraints between actions.
|
||||||
|
@ -193,7 +267,8 @@ class Admin::MembersController < OrbitMemberController
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def get_info_and_roles
|
def get_info_and_roles
|
||||||
@roles = Role.excludes('disabled' => true)
|
@roles = Role.excludes(disabled: true)
|
||||||
|
@infos = MemberProfileField.excludes(disabled: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_attribute
|
def set_attribute
|
||||||
|
|
|
@ -10,15 +10,15 @@ module AttributeFieldsHelper
|
||||||
|
|
||||||
include OrbitFormHelper
|
include OrbitFormHelper
|
||||||
|
|
||||||
def block_helper(user,index,disable = false)
|
def block_helper(member,index,disable = false)
|
||||||
unless self.disabled
|
unless self.disabled
|
||||||
@index = index
|
@index = index
|
||||||
@markup_options = markup_options.merge(:disabled=>disable,:func=>"input_unit")
|
@markup_options = markup_options.merge(:disabled=>disable,:func=>"input_unit")
|
||||||
@user = user
|
@member = member
|
||||||
@attribute_value = @user.get_value_from_field_id(id)
|
@attribute_value = @member.get_value_from_field_id(id)
|
||||||
@new_attribute = @attribute_value.nil?
|
@new_attribute = @attribute_value.nil?
|
||||||
@attribute_value = @attribute_value || @user.attribute_values.build( attribute_field_id: id )
|
@attribute_value = @attribute_value || @member.member_profile_field_values.build(member_profile_field: id)
|
||||||
@prefiled_value = @attribute_value.value
|
@prefiled_value = @attribute_value.value rescue nil
|
||||||
@panel_setting = self.get_data
|
@panel_setting = self.get_data
|
||||||
return instance_eval("render_#{markup}") #rescue ""
|
return instance_eval("render_#{markup}") #rescue ""
|
||||||
|
|
||||||
|
@ -179,12 +179,17 @@ module AttributeFieldsHelper
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
|
def valid_locales
|
||||||
|
site = Site.first
|
||||||
|
site.valid_locales
|
||||||
|
end
|
||||||
|
|
||||||
def lang_panel_tabbable_wrapper(add_more_params,&block)
|
def lang_panel_tabbable_wrapper(add_more_params,&block)
|
||||||
add_more_counter = ''
|
add_more_counter = ''
|
||||||
|
|
||||||
if self.markup=='text_area' #or self.markup=='address'
|
if self.markup=='text_area' #or self.markup=='address'
|
||||||
|
|
||||||
tmp1 = VALID_LOCALES.collect do |key|
|
tmp1 = valid_locales.collect do |key|
|
||||||
value = @prefiled_value[key] rescue nil
|
value = @prefiled_value[key] rescue nil
|
||||||
# div_class_ary = ["tab-pane" ,"fade","#{get_pairing_tab_class({})}_#{key}"]
|
# div_class_ary = ["tab-pane" ,"fade","#{get_pairing_tab_class({})}_#{key}"]
|
||||||
div_class_ary = ["tab-pane" ,"fade"]
|
div_class_ary = ["tab-pane" ,"fade"]
|
||||||
|
@ -205,7 +210,7 @@ protected
|
||||||
|
|
||||||
|
|
||||||
tmp2 = content_tag(:div,:class => 'btn-group', :data=>{:toggle=>"buttons-radio"}) do
|
tmp2 = content_tag(:div,:class => 'btn-group', :data=>{:toggle=>"buttons-radio"}) do
|
||||||
buff2 = VALID_LOCALES.each.collect do |key|
|
buff2 = valid_locales.each.collect do |key|
|
||||||
# link_entry = self.add_more ? "#{add_more_tab(:tab_btn,loop_counter,key)}" : "#tab"+id.to_s+"_#{key}"
|
# link_entry = self.add_more ? "#{add_more_tab(:tab_btn,loop_counter,key)}" : "#tab"+id.to_s+"_#{key}"
|
||||||
link_entry_ary = ["##{get_pairing_tab_class({})}","_#{key}"]
|
link_entry_ary = ["##{get_pairing_tab_class({})}","_#{key}"]
|
||||||
link_entry_ary << ".add_more_item_#{add_more_counter}" if can_add_more
|
link_entry_ary << ".add_more_item_#{add_more_counter}" if can_add_more
|
||||||
|
@ -229,7 +234,7 @@ protected
|
||||||
tmp1 =
|
tmp1 =
|
||||||
content_tag :div,:class=> "tab-content" do
|
content_tag :div,:class=> "tab-content" do
|
||||||
|
|
||||||
buff = VALID_LOCALES.collect do |key|
|
buff = valid_locales.collect do |key|
|
||||||
value = @prefiled_value[key] rescue nil
|
value = @prefiled_value[key] rescue nil
|
||||||
# div_class_ary = ["tab-pane" ,"fade","#{get_pairing_tab_class({})}_#{key}"]
|
# div_class_ary = ["tab-pane" ,"fade","#{get_pairing_tab_class({})}_#{key}"]
|
||||||
div_class_ary = ["tab-pane" ,"fade"]
|
div_class_ary = ["tab-pane" ,"fade"]
|
||||||
|
@ -254,7 +259,7 @@ protected
|
||||||
end
|
end
|
||||||
|
|
||||||
tmp2 = content_tag(:div,:class => 'btn-group', :data=>{:toggle=>"buttons-radio"}) do
|
tmp2 = content_tag(:div,:class => 'btn-group', :data=>{:toggle=>"buttons-radio"}) do
|
||||||
buff2 = VALID_LOCALES.each.collect do |key|
|
buff2 = valid_locales.each.collect do |key|
|
||||||
# link_entry = self.add_more ? "#{add_more_tab(:tab_btn,loop_counter,key)}" : "#tab"+id.to_s+"_#{key}"
|
# link_entry = self.add_more ? "#{add_more_tab(:tab_btn,loop_counter,key)}" : "#tab"+id.to_s+"_#{key}"
|
||||||
link_entry_ary = ["##{get_pairing_tab_class({})}","_#{key}"]
|
link_entry_ary = ["##{get_pairing_tab_class({})}","_#{key}"]
|
||||||
link_entry_ary << ".add_more_item_#{add_more_counter}" if can_add_more
|
link_entry_ary << ".add_more_item_#{add_more_counter}" if can_add_more
|
||||||
|
@ -342,14 +347,14 @@ protected
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
temp = label + content_tag(:div, multipleInputs + add_more_unt, :class=>'controls add-input')
|
temp = form_label + content_tag(:div, multipleInputs + add_more_unt, :class=>'controls add-input')
|
||||||
|
|
||||||
result = content_tag(:div,temp,:class=>div_class)
|
result = content_tag(:div,temp,:class=>div_class)
|
||||||
|
|
||||||
# result = label + multipleInputs + add_more_unt
|
# result = label + multipleInputs + add_more_unt
|
||||||
# result = label + 一堆的輸入框(要用 multipleInput editMore 包起來) + add_more btn + hidden_fields
|
# result = label + 一堆的輸入框(要用 multipleInput editMore 包起來) + add_more btn + hidden_fields
|
||||||
else
|
else
|
||||||
temp = label + content_tag(:div, controls_wrapper(&block), :class=>'controls')
|
temp = form_label + content_tag(:div, controls_wrapper(&block), :class=>'controls')
|
||||||
result = content_tag(:div,temp,:class=>div_class)
|
result = content_tag(:div,temp,:class=>div_class)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -358,13 +363,13 @@ protected
|
||||||
|
|
||||||
# address = content_tag :div,:class=>"multipleInput editMore" do
|
# address = content_tag :div,:class=>"multipleInput editMore" do
|
||||||
address = content_tag :div,:class=>"control-group" do
|
address = content_tag :div,:class=>"control-group" do
|
||||||
label + content_tag(:div, controls_wrapper(&block), :class=>'controls add-input')
|
form_label + content_tag(:div, controls_wrapper(&block), :class=>'controls add-input')
|
||||||
end # of div multipleInput editMore
|
end # of div multipleInput editMore
|
||||||
|
|
||||||
result = address
|
result = address
|
||||||
|
|
||||||
else
|
else
|
||||||
temp = label + content_tag(:div, controls_wrapper(&block), :class=>'controls')
|
temp = form_label + content_tag(:div, controls_wrapper(&block), :class=>'controls')
|
||||||
result = content_tag(:div,temp,:class=>div_class)
|
result = content_tag(:div,temp,:class=>div_class)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -395,7 +400,7 @@ protected
|
||||||
|
|
||||||
def end_block
|
def end_block
|
||||||
if @new_attribute
|
if @new_attribute
|
||||||
hidden_field_tag(get_basic_field_name_base+"[attribute_field_id]",id,:for=>"field_#{@index}")
|
hidden_field_tag(get_basic_field_name_base+"[member_profile_field_id]",id,:for=>"field_#{@index}")
|
||||||
else
|
else
|
||||||
hidden_field_tag(get_basic_field_name_base+"[id]",@attribute_value.id,:for=>"field_#{@index}")
|
hidden_field_tag(get_basic_field_name_base+"[id]",@attribute_value.id,:for=>"field_#{@index}")
|
||||||
end
|
end
|
||||||
|
@ -420,9 +425,9 @@ protected
|
||||||
|
|
||||||
def get_basic_field_name_base
|
def get_basic_field_name_base
|
||||||
if @new_attribute
|
if @new_attribute
|
||||||
"user[new_attribute_values][#{@index}]"
|
"member_profile_field_value[#{@index}]"
|
||||||
else
|
else
|
||||||
"user[attribute_values][#{@index}]"
|
"member_profile_field_values[#{@index}]"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
class MemberProfile
|
class MemberProfile
|
||||||
include Mongoid::Document
|
include Mongoid::Document
|
||||||
include Mongoid::Timestamps
|
include Mongoid::Timestamps
|
||||||
|
include Mongoid::Tree
|
||||||
|
include Mongoid::Tree::Ordering
|
||||||
|
|
||||||
field :first_name, type: String, localize: true
|
field :first_name, type: String, localize: true
|
||||||
field :last_name, type: String, localize: true
|
field :last_name, type: String, localize: true
|
||||||
|
@ -12,14 +14,21 @@ class MemberProfile
|
||||||
field :personal_website
|
field :personal_website
|
||||||
field :autobiography, type: String, localize: true
|
field :autobiography, type: String, localize: true
|
||||||
field :email, type: String
|
field :email, type: String
|
||||||
|
field :position, type: Integer
|
||||||
|
|
||||||
VALID_EMAIL_FORMAT = /\A[^@\s]+@([^@.\s]+\.)+[^@.\s]+\z/
|
VALID_EMAIL_FORMAT = /\A[^@\s]+@([^@.\s]+\.)+[^@.\s]+\z/
|
||||||
validates :email, uniqueness: true, format: { with: VALID_EMAIL_FORMAT }
|
validates :email, uniqueness: true, format: { with: VALID_EMAIL_FORMAT }
|
||||||
|
validates :position, uniqueness: true
|
||||||
|
|
||||||
has_one :user
|
has_one :user
|
||||||
has_and_belongs_to_many :roles
|
has_and_belongs_to_many :roles
|
||||||
has_and_belongs_to_many :role_statuses
|
has_and_belongs_to_many :role_statuses
|
||||||
|
|
||||||
|
has_many :member_profile_field_values
|
||||||
|
accepts_nested_attributes_for :member_profile_field_values
|
||||||
|
|
||||||
|
before_save :assign_default_position, :if => :assign_default_position?
|
||||||
|
|
||||||
mount_uploader :avatar, AvatarUploader
|
mount_uploader :avatar, AvatarUploader
|
||||||
paginates_per 10
|
paginates_per 10
|
||||||
|
|
||||||
|
@ -38,4 +47,19 @@ class MemberProfile
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_attribute_values
|
||||||
|
@attribute_values ||= self.member_profile_field_values rescue nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_value_from_field_id(field_id)
|
||||||
|
values = get_attribute_values
|
||||||
|
value = values.detect {|value| value.attribute_field_id == field_id} rescue nil
|
||||||
|
value ? value : nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_default_position?
|
||||||
|
self.position.nil? || self.parent_id_changed?
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,7 +21,7 @@ class MemberProfileField
|
||||||
field :typeD, type: Hash, default: {cross_lang: false}
|
field :typeD, type: Hash, default: {cross_lang: false}
|
||||||
field :typeE, type: Hash, default: {}
|
field :typeE, type: Hash, default: {}
|
||||||
|
|
||||||
embeds_many :member_profile_field_values
|
has_many :member_profile_field_values
|
||||||
|
|
||||||
def markup_value
|
def markup_value
|
||||||
get_data["option_list"]
|
get_data["option_list"]
|
||||||
|
|
|
@ -5,6 +5,8 @@ class MemberProfileFieldValue
|
||||||
|
|
||||||
field :key
|
field :key
|
||||||
field :address_key
|
field :address_key
|
||||||
|
field :value
|
||||||
|
|
||||||
embedded_in :member_profile_field
|
belongs_to :member_profile_field
|
||||||
|
belongs_to :member_profile
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
<div id="list-view">
|
||||||
|
<div id="member-card" class="mini-layout-body">
|
||||||
|
<ul id="card-list" class="checkbox-card clearfix">
|
||||||
|
<% @members.each do |member| %>
|
||||||
|
<li class="filter-item" data-user-id="<%= member.id %>">
|
||||||
|
<label>
|
||||||
|
<div class="user-pic">
|
||||||
|
<%= show_avatar(member) %>
|
||||||
|
</div>
|
||||||
|
<span class="user-name"><%= member.name %></span>
|
||||||
|
<span><%= member.email %></span>
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
<% end %>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
dragMode();
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -0,0 +1,44 @@
|
||||||
|
<div id="list-view">
|
||||||
|
<table id="member-list" class="table main-list">
|
||||||
|
<thead>
|
||||||
|
<tr class="sort-header">
|
||||||
|
<th class="gender"></th>
|
||||||
|
<th class="span2"><a href="#"><%= t(:position) %></a></th>
|
||||||
|
<th class="span4"><a href="#"><%= t(:name) %></a></th>
|
||||||
|
<th><a href="#"><%= t(:email) %></a></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% @members.each do |member| %>
|
||||||
|
<%
|
||||||
|
case member.sex
|
||||||
|
when 'male'
|
||||||
|
member_sex = 'gender-man'
|
||||||
|
when 'female'
|
||||||
|
member_sex = 'gender-woman'
|
||||||
|
else
|
||||||
|
member_sex = 'gender-none'
|
||||||
|
end
|
||||||
|
%>
|
||||||
|
<tr id="<%= dom_id member %>">
|
||||||
|
<td class="<%= member_sex %>"></td>
|
||||||
|
<td><%= link_to member.position, '#', class: 'edit_position', 'data-user-id' => member.id %></td>
|
||||||
|
<td><%= link_to member.name, admin_member_path(member) %></td>
|
||||||
|
<td><%= member.email %></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bottomnav clearfix">
|
||||||
|
<div class="action pull-right">
|
||||||
|
<%= link_to t(:update_), '#', class: "btn btn-primary pull-right" %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
typeMode();
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="action pull-right">
|
<div class="action pull-right">
|
||||||
<% if params[:action] != "unapproved_members" %>
|
<% if params[:action] != "unapproved_members" %>
|
||||||
<% if current_user.is_admin? %>
|
<% if current_user.is_admin? %>
|
||||||
<%= link_to t(:edit_order),new_admin_member_path ,:class => "btn btn-primary" %>
|
<%= link_to t(:edit_order), edit_order_list_admin_members_path,:class => "btn btn-primary" %>
|
||||||
<%= link_to(new_admin_member_path,:class=> "btn btn-primary") do %>
|
<%= link_to(new_admin_member_path,:class=> "btn btn-primary") do %>
|
||||||
<i class="icon-plus"></i><%= t(:add) %>
|
<i class="icon-plus"></i><%= t(:add) %>
|
||||||
<% end -%>
|
<% end -%>
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<div class="attributes">
|
||||||
|
<div class="attributes-header clearfix">
|
||||||
|
<h4><%= info.title %></h4>
|
||||||
|
</div>
|
||||||
|
<div class="attributes-body">
|
||||||
|
<%= info.block_helper(@member, @form_index)%>
|
||||||
|
<% @form_index = @form_index +1 %>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1 @@
|
||||||
|
<%=render partial: "info", collection: @infos%>
|
|
@ -22,7 +22,9 @@
|
||||||
<div class="quick-edit">
|
<div class="quick-edit">
|
||||||
<ul class="nav nav-pills">
|
<ul class="nav nav-pills">
|
||||||
<%= content_tag(:li, link_to(t(:edit),edit_admin_member_path(member_for_listing))) if current_user.is_admin? %>
|
<%= content_tag(:li, link_to(t(:edit),edit_admin_member_path(member_for_listing))) if current_user.is_admin? %>
|
||||||
|
<% if member_for_listing.user.present? %>
|
||||||
<%= content_tag(:li, link_to(t("users.setting_privilege"),admin_member_edit_privilege_path(member_for_listing))) if current_user.is_admin? and current_user.id != (member_for_listing.user.id if member_for_listing.user.present? ) %>
|
<%= content_tag(:li, link_to(t("users.setting_privilege"),admin_member_edit_privilege_path(member_for_listing))) if current_user.is_admin? and current_user.id != (member_for_listing.user.id if member_for_listing.user.present? ) %>
|
||||||
|
<% end %>
|
||||||
<%= content_tag(:li, link_to(t(:delete_),admin_member_path(member_for_listing, :at=>params[:at]), :confirm => t(:sure?), :method => :delete, :class=>"text-error", :remote => true)) if current_user.is_admin? %>
|
<%= content_tag(:li, link_to(t(:delete_),admin_member_path(member_for_listing, :at=>params[:at]), :confirm => t(:sure?), :method => :delete, :class=>"text-error", :remote => true)) if current_user.is_admin? %>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<p class="<%= @user_sex%>"></p>
|
<p class="<%= @user_sex%>"></p>
|
||||||
<div class="action">
|
<div class="action">
|
||||||
<%= link_to(content_tag(:i, nil, :class => 'icon-edit'),edit_admin_member_path(member_for_summary),:class=>"edit" ) if current_user.is_admin?%>
|
<%= link_to(content_tag(:i, nil, :class => 'icon-edit'),edit_admin_member_path(member_for_summary),:class=>"edit" ) if current_user.is_admin?%>
|
||||||
<%= link_to(content_tag(:i, nil, :class => 'icon-key'),:class=>"key" ) if current_user.is_admin? and current_user.id != member_for_summary.id %>
|
<%= link_to(content_tag(:i, nil, :class => 'icon-key'),admin_member_edit_privilege_path(member_for_summary),:class=>"key" ) if current_user.is_admin? and current_user.id != member_for_summary.id %>
|
||||||
<%= link_to(content_tag(:i, nil, :class => 'icon-trash'), admin_members_path(member_for_summary, :at=>params[:at]), :confirm => t(:sure?), :method => :delete, :class=>"trash", :remote => true) if current_user.is_admin? %>
|
<%= link_to(content_tag(:i, nil, :class => 'icon-trash'), admin_members_path(member_for_summary, :at=>params[:at]), :confirm => t(:sure?), :method => :delete, :class=>"trash", :remote => true) if current_user.is_admin? %>
|
||||||
</div>
|
</div>
|
||||||
<%= image_tag(member_for_summary.avatar) %>
|
<%= image_tag(member_for_summary.avatar) %>
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
<h4><span><%= show_roles.title %><%= t(:role_info)%></span></h4>
|
<h4><span><%= show_roles.title %><%= t(:role_info)%></span></h4>
|
||||||
<dl>
|
<dl>
|
||||||
<dt><%= t('status') %></dt>
|
<dt><%= t('status') %></dt>
|
||||||
<dd><%= show_attribute_value(@user.role_statuses.where(:role_id=>show_roles.id).map{|t|t.title.to_s}.join(',')) rescue '' %></dd>
|
<dd><%= @member.role_statuses.where(role_id: show_roles.id).map{|t|t.title.to_s}.join(',') rescue '' %></dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
$('#order_content').html("<%= j render 'edit_order_list' %>")
|
|
@ -15,6 +15,9 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
<dt><%= t('users.sex')%></dt>
|
<dt><%= t('users.sex')%></dt>
|
||||||
<dd><%= t("users.#{(@member.sex.nil? ? 'unknown' : @member.sex)}") %></dd>
|
<dd><%= t("users.#{(@member.sex.nil? ? 'unknown' : @member.sex)}") %></dd>
|
||||||
|
<% items.each do |item| %>
|
||||||
|
<dt><%= item.member_profile_field.title %></dt>
|
||||||
|
<dd><%= item.value %></dd>
|
||||||
|
<% end -%>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
|
@ -0,0 +1,45 @@
|
||||||
|
<%= form_for @user, :html => { :class=>"form-horizontal main-forms", :id=>"user-forms"} do |f| %>
|
||||||
|
|
||||||
|
<div class="attributes">
|
||||||
|
<div class="attributes-header clearfix">
|
||||||
|
<h4><%=t(:sys_basic_id_form)%></h4>
|
||||||
|
</div>
|
||||||
|
<div class="attributes-body">
|
||||||
|
|
||||||
|
<!-- Account -->
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label muted" for="account">
|
||||||
|
<label for="user_name" class="control-label"><%= t("users.user_id")%></label>
|
||||||
|
</label>
|
||||||
|
<div class="controls add-input">
|
||||||
|
<%= f.text_field :user_name, :class=>"input-medium", :id=>"account", :placeholder=>"#{t('users.user_id')}" %>
|
||||||
|
<span class="help-block"><%= t("users.user_id_note")%></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Password -->
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label muted" for="password">
|
||||||
|
<label for="password" class="control-label"><%= t("users.new_password")%></label>
|
||||||
|
</label>
|
||||||
|
<div class="controls add-input">
|
||||||
|
<%= f.password_field :password, :class=>"input-medium", :id=>"password" %>
|
||||||
|
<span class="help-block"><%= t("users.new_password_note")%></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Confirm Password -->
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label muted" for="confirm_password">
|
||||||
|
<label for="password_confirmation" class="control-label"><%= t("users.new_password_confirmation")%></label>
|
||||||
|
</label>
|
||||||
|
<div class="controls add-input">
|
||||||
|
<%= f.password_field :password_confirmation, :class=>"input-medium", :id=>"confirm_password" %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= f.hidden_field :approved, value: true if current_user.is_admin? %>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
|
@ -0,0 +1 @@
|
||||||
|
$("#<%= dom_id @member_profile %>").remove();
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
<%= render partial: 'user_basic_passwd'%>
|
<%= render partial: 'user_basic_passwd'%>
|
||||||
<%= render partial: 'member_basic', locals: {f: f}%>
|
<%= render partial: 'member_basic', locals: {f: f}%>
|
||||||
|
<%= render partial: "infos"%>
|
||||||
<%= render partial: 'roles', locals: {f: f} %>
|
<%= render partial: 'roles', locals: {f: f} %>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
<% content_for :side_bar do %>
|
||||||
|
<%= render :partial => 'admin/members/side_bar' %>
|
||||||
|
<% end %>
|
||||||
|
<% content_for :page_specific_css do %>
|
||||||
|
<%= stylesheet_link_tag "lib/member" %>
|
||||||
|
<%= stylesheet_link_tag "lib/checkbox-card" %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% content_for :right_nav do %>
|
||||||
|
<div class="view-switch btn-group pull-right" data-toggle="buttons-radio">
|
||||||
|
<%= link_to content_tag(:i, nil, class: 'icon-list'), edit_order_list_admin_members_path, class: "btn btn-small#{' active' if @type.eql?('list')}" %>
|
||||||
|
<%= link_to content_tag(:i, nil, class: 'icon-th'), edit_order_card_admin_members_path, class: "btn btn-small#{' active' if @type.eql?('card')}" %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div id="order_content">
|
||||||
|
<% case @type %>
|
||||||
|
<% when 'card' %>
|
||||||
|
<%= render 'edit_order_card' %>
|
||||||
|
<% when 'list' %>
|
||||||
|
<%= render 'edit_order_list' %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% content_for :page_specific_javascript do %>
|
||||||
|
<%= javascript_include_tag "jquery.ui.sortable" %>
|
||||||
|
<%= javascript_include_tag "lib/jquery.ui.touch-punch.min" %>
|
||||||
|
<%= javascript_include_tag "lib/jquery.lite.image.resize" %>
|
||||||
|
<%= javascript_include_tag "lib/member/sort" %>
|
||||||
|
<% end %>
|
|
@ -27,8 +27,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
<div class="filter-group accordion-group">
|
<div class="filter-group accordion-group">
|
||||||
<div class="accordion-body collapse" id="collapse-role">
|
<div class="accordion-body collapse" id="collapse-role">
|
||||||
|
<%= render :partial => "filter", locals: {:role => @roles}%>
|
||||||
<%= render :partial => "filter"%>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
<div id="basic-area" class="input-area">
|
<div id="basic-area" class="input-area">
|
||||||
<%= render partial: 'user_basic_passwd'%>
|
<%= render partial: 'user_basic_passwd'%>
|
||||||
<%= render partial: 'member_basic', locals: {f: f}%>
|
<%= render partial: 'member_basic', locals: {f: f}%>
|
||||||
|
<%= render partial: "infos"%>
|
||||||
<%= render partial: 'roles', locals: { f: f } %>
|
<%= render partial: 'roles', locals: { f: f } %>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
<% content_for :side_bar do %>
|
||||||
|
<%= render :partial => 'admin/members/side_bar' %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% content_for :page_specific_css do -%>
|
||||||
|
<%= stylesheet_link_tag "lib/wrap-nav.css" %>
|
||||||
|
<%= stylesheet_link_tag "lib/pageslide.css" %>
|
||||||
|
<%= stylesheet_link_tag "lib/main-forms.css" %>
|
||||||
|
<%= stylesheet_link_tag "lib/fileupload.css" %>
|
||||||
|
<%= stylesheet_link_tag "lib/togglebox.css" %>
|
||||||
|
<% end -%>
|
||||||
|
<% content_for :page_specific_javascript do -%>
|
||||||
|
<%= javascript_include_tag "lib/jquery.tmpl.min.js" %>
|
||||||
|
<%= javascript_include_tag "lib/bootstrap-fileupload.js" %>
|
||||||
|
<%= javascript_include_tag "lib/member/role-forms.js" %>
|
||||||
|
<%= javascript_include_tag "lib/member/textarea-lang-btn.js" %>
|
||||||
|
<% end -%>
|
||||||
|
|
||||||
|
|
||||||
|
<%= form_for @member, :url => admin_member_path(@member), :html => { :multipart => true , :class=>"form-horizontal main-forms", :id=>"user-forms"} do |f| %>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<div id="basic-area" class="input-area">
|
||||||
|
|
||||||
|
<%= render :partial => 'user_setting_account', :locals => {:f => f}%>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
<%= link_back('btn') %>
|
||||||
|
<%= hidden_field_tag 'edit_type', 'setting_account' %>
|
||||||
|
<%= link_to t(:update_), "#", :class=>"btn btn-primary returnDecide", :onclick=>"$('#edit_user_#{@user.id}').submit()" %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<% end -%>
|
|
@ -20,14 +20,14 @@
|
||||||
<small class="muted"><%= @member.email %></small>
|
<small class="muted"><%= @member.email %></small>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<%= link_to("<i class='icon-edit'></i> #{t(:edit)}".html_safe,edit_admin_member_path(@member.id),:class=>"btn btn-mini" ) if current_user.is_admin?%>
|
<%= link_to("<i class='icon-edit'></i> #{t(:edit)}".html_safe,edit_admin_member_path(@member.id),:class=>"btn btn-mini" ) if current_user.is_admin?%>
|
||||||
<%= link_to("<i class='icons-cycle'></i> #{t("users.change_passwd")}".html_safe,admin_member_edit_passwd_path(@member),:class=>"btn btn-mini" ) if current_user.is_admin? and current_user.id != @member.user.id %>
|
<%= link_to("<i class='icons-cycle'></i> #{t("users.change_passwd")}".html_safe,admin_member_edit_passwd_path(@member),:class=>"btn btn-mini" ) if current_user.is_admin? and current_user.id != @member.user.id rescue nil %>
|
||||||
<%= link_to("<i class='icons-lock-open'></i> #{t("users.setting_privilege")}".html_safe,admin_member_edit_privilege_path(@member),:class=>"btn btn-mini" ) if current_user.is_admin? and current_user.id != @member.user.id %>
|
<%= link_to("<i class='icons-lock-open'></i> #{t("users.setting_privilege")}".html_safe,admin_member_edit_privilege_path(@member),:class=>"btn btn-mini" ) if current_user.is_admin? and current_user.id != @member.user.id rescue nil%>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="member-roles" class="nano">
|
<div id="member-roles" class="nano">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<%= render :partial=> "user_profile",:locals=>{:role_class=>"basic",:i18n=>"profile"} %>
|
<%= render :partial=> "user_profile",:locals=>{:role_class=>"basic",:i18n=>"profile", :items=>@custom_fields} %>
|
||||||
<%= render :partial=> "show_roles",collection: @member.roles %>
|
<%= render :partial=> "show_roles",collection: @member.roles %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
$('#order_content').html("<%= j render 'edit_order_list' %>")
|
|
@ -81,9 +81,17 @@ Orbit::Application.routes.draw do
|
||||||
get 'get_month_traffic'
|
get 'get_month_traffic'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
get "members/unapproved_members" => "members#unapproved_members"
|
get "members/unapproved_members" => "members#unapproved_members"
|
||||||
|
|
||||||
resources :members do
|
resources :members do
|
||||||
|
collection do
|
||||||
|
get 'edit_order_card'
|
||||||
|
get 'edit_order_list'
|
||||||
|
post 'update_order_card'
|
||||||
|
post 'update_order_list'
|
||||||
|
end
|
||||||
|
match "setting_account" => "members#setting_account" ,:as => :setting_account, via: [:get, :post]
|
||||||
match "edit_passwd" => "members#edit_passwd" ,:as => :edit_passwd, via: [:get, :post]
|
match "edit_passwd" => "members#edit_passwd" ,:as => :edit_passwd, via: [:get, :post]
|
||||||
match "accept_member" => "members#accept_member" ,:as => :accept_member, via: [:get, :post]
|
match "accept_member" => "members#accept_member" ,:as => :accept_member, via: [:get, :post]
|
||||||
match "edit_privilege" => "members#edit_privilege" ,:as => :edit_privilege, via: [:get, :post]
|
match "edit_privilege" => "members#edit_privilege" ,:as => :edit_privilege, via: [:get, :post]
|
||||||
|
|
|
@ -0,0 +1,442 @@
|
||||||
|
module Mongoid
|
||||||
|
##
|
||||||
|
# = Mongoid::Tree
|
||||||
|
#
|
||||||
|
# This module extends any Mongoid document with tree functionality.
|
||||||
|
#
|
||||||
|
# == Usage
|
||||||
|
#
|
||||||
|
# Simply include the module in any Mongoid document:
|
||||||
|
#
|
||||||
|
# class Node
|
||||||
|
# include Mongoid::Document
|
||||||
|
# include Mongoid::Tree
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# === Using the tree structure
|
||||||
|
#
|
||||||
|
# Each document references many children. You can access them using the <tt>#children</tt> method.
|
||||||
|
#
|
||||||
|
# node = Node.create
|
||||||
|
# node.children.create
|
||||||
|
# node.children.count # => 1
|
||||||
|
#
|
||||||
|
# Every document references one parent (unless it's a root document).
|
||||||
|
#
|
||||||
|
# node = Node.create
|
||||||
|
# node.parent # => nil
|
||||||
|
# node.children.create
|
||||||
|
# node.children.first.parent # => node
|
||||||
|
#
|
||||||
|
# === Destroying
|
||||||
|
#
|
||||||
|
# Mongoid::Tree does not handle destroying of nodes by default. However it provides
|
||||||
|
# several strategies that help you to deal with children of deleted documents. You can
|
||||||
|
# simply add them as <tt>before_destroy</tt> callbacks.
|
||||||
|
#
|
||||||
|
# Available strategies are:
|
||||||
|
#
|
||||||
|
# * :nullify_children -- Sets the children's parent_id to null
|
||||||
|
# * :move_children_to_parent -- Moves the children to the current document's parent
|
||||||
|
# * :destroy_children -- Destroys all children by calling their #destroy method (invokes callbacks)
|
||||||
|
# * :delete_descendants -- Deletes all descendants using a database query (doesn't invoke callbacks)
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# class Node
|
||||||
|
# include Mongoid::Document
|
||||||
|
# include Mongoid::Tree
|
||||||
|
#
|
||||||
|
# before_destroy :nullify_children
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# === Callbacks
|
||||||
|
#
|
||||||
|
# Mongoid::Tree offers callbacks for its rearranging process. This enables you to
|
||||||
|
# rebuild certain fields when the document was moved in the tree. Rearranging happens
|
||||||
|
# before the document is validated. This gives you a chance to validate your additional
|
||||||
|
# changes done in your callbacks. See ActiveModel::Callbacks and ActiveSupport::Callbacks
|
||||||
|
# for further details on callbacks.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# class Page
|
||||||
|
# include Mongoid::Document
|
||||||
|
# include Mongoid::Tree
|
||||||
|
#
|
||||||
|
# after_rearrange :rebuild_path
|
||||||
|
#
|
||||||
|
# field :slug
|
||||||
|
# field :path
|
||||||
|
#
|
||||||
|
# private
|
||||||
|
#
|
||||||
|
# def rebuild_path
|
||||||
|
# self.path = self.ancestors_and_self.collect(&:slug).join('/')
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
module Tree
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
autoload :Ordering, 'mongoid/tree/ordering'
|
||||||
|
autoload :Traversal, 'mongoid/tree/traversal'
|
||||||
|
|
||||||
|
included do
|
||||||
|
has_many :children, :class_name => self.name, :foreign_key => :parent_id, :inverse_of => :parent, :validate => false
|
||||||
|
|
||||||
|
belongs_to :parent, :class_name => self.name, :inverse_of => :children, :index => true, :validate => false
|
||||||
|
|
||||||
|
field :parent_ids, :type => Array, :default => []
|
||||||
|
index :parent_ids => 1
|
||||||
|
|
||||||
|
field :depth, :type => Integer
|
||||||
|
index :depth => 1
|
||||||
|
|
||||||
|
set_callback :save, :after, :rearrange_children, :if => :rearrange_children?
|
||||||
|
set_callback :validation, :before do
|
||||||
|
run_callbacks(:rearrange) { rearrange }
|
||||||
|
end
|
||||||
|
|
||||||
|
validate :position_in_tree
|
||||||
|
|
||||||
|
define_model_callbacks :rearrange, :only => [:before, :after]
|
||||||
|
|
||||||
|
class_eval "def base_class; ::#{self.name}; end"
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# This module implements class methods that will be available
|
||||||
|
# on the document that includes Mongoid::Tree
|
||||||
|
module ClassMethods
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns the first root document
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# Node.root
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Document] The first root document
|
||||||
|
def root
|
||||||
|
roots.first
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns all root documents
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# Node.roots
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Criteria] Mongoid criteria to retrieve all root documents
|
||||||
|
def roots
|
||||||
|
where(:parent_id => nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns all leaves (be careful, currently involves two queries)
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# Node.leaves
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Criteria] Mongoid criteria to retrieve all leave nodes
|
||||||
|
def leaves
|
||||||
|
where(:_id.nin => only(:parent_id).collect(&:parent_id))
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# @!method before_rearrange
|
||||||
|
# @!scope class
|
||||||
|
#
|
||||||
|
# Sets a callback that is called before the document is rearranged
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# class Node
|
||||||
|
# include Mongoid::Document
|
||||||
|
# include Mongoid::Tree
|
||||||
|
#
|
||||||
|
# before_rearrage :do_something
|
||||||
|
#
|
||||||
|
# private
|
||||||
|
#
|
||||||
|
# def do_something
|
||||||
|
# # ...
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# @note Generated by ActiveSupport
|
||||||
|
#
|
||||||
|
# @return [undefined]
|
||||||
|
|
||||||
|
##
|
||||||
|
# @!method after_rearrange
|
||||||
|
# @!scope class
|
||||||
|
#
|
||||||
|
# Sets a callback that is called after the document is rearranged
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# class Node
|
||||||
|
# include Mongoid::Document
|
||||||
|
# include Mongoid::Tree
|
||||||
|
#
|
||||||
|
# after_rearrange :do_something
|
||||||
|
#
|
||||||
|
# private
|
||||||
|
#
|
||||||
|
# def do_something
|
||||||
|
# # ...
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# @note Generated by ActiveSupport
|
||||||
|
#
|
||||||
|
# @return [undefined]
|
||||||
|
|
||||||
|
##
|
||||||
|
# @!method children
|
||||||
|
# Returns a list of the document's children. It's a <tt>references_many</tt> association.
|
||||||
|
#
|
||||||
|
# @note Generated by Mongoid
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Criteria] Mongoid criteria to retrieve the document's children
|
||||||
|
|
||||||
|
##
|
||||||
|
# @!method parent
|
||||||
|
# Returns the document's parent (unless it's a root document). It's a <tt>referenced_in</tt> association.
|
||||||
|
#
|
||||||
|
# @note Generated by Mongoid
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Document] The document's parent document
|
||||||
|
|
||||||
|
##
|
||||||
|
# @!method parent=(document)
|
||||||
|
# Sets this documents parent document.
|
||||||
|
#
|
||||||
|
# @note Generated by Mongoid
|
||||||
|
#
|
||||||
|
# @param [Mongoid::Tree] document
|
||||||
|
|
||||||
|
##
|
||||||
|
# @!method parent_ids
|
||||||
|
# Returns a list of the document's parent_ids, starting with the root node.
|
||||||
|
#
|
||||||
|
# @note Generated by Mongoid
|
||||||
|
#
|
||||||
|
# @return [Array<BSON::ObjectId>] The ids of the document's ancestors
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns the depth of this document (number of ancestors)
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# Node.root.depth # => 0
|
||||||
|
# Node.root.children.first.depth # => 1
|
||||||
|
#
|
||||||
|
# @return [Fixnum] Depth of this document
|
||||||
|
def depth
|
||||||
|
super || parent_ids.count
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Is this document a root node (has no parent)?
|
||||||
|
#
|
||||||
|
# @return [Boolean] Whether the document is a root node
|
||||||
|
def root?
|
||||||
|
parent_id.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Is this document a leaf node (has no children)?
|
||||||
|
#
|
||||||
|
# @return [Boolean] Whether the document is a leaf node
|
||||||
|
def leaf?
|
||||||
|
children.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns this document's root node. Returns `self` if the
|
||||||
|
# current document is a root node
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# node = Node.find(...)
|
||||||
|
# node.root
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Document] The documents root node
|
||||||
|
def root
|
||||||
|
if parent_ids.present?
|
||||||
|
base_class.find(parent_ids.first)
|
||||||
|
else
|
||||||
|
self.root? ? self : self.parent.root
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns a chainable criteria for this document's ancestors
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Criteria] Mongoid criteria to retrieve the documents ancestors
|
||||||
|
def ancestors
|
||||||
|
base_class.where(:_id.in => parent_ids).order(:depth => :asc)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns an array of this document's ancestors and itself
|
||||||
|
#
|
||||||
|
# @return [Array<Mongoid::Document>] Array of the document's ancestors and itself
|
||||||
|
def ancestors_and_self
|
||||||
|
ancestors + [self]
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Is this document an ancestor of the other document?
|
||||||
|
#
|
||||||
|
# @param [Mongoid::Tree] other document to check against
|
||||||
|
#
|
||||||
|
# @return [Boolean] The document is an ancestor of the other document
|
||||||
|
def ancestor_of?(other)
|
||||||
|
other.parent_ids.include?(self.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns a chainable criteria for this document's descendants
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Criteria] Mongoid criteria to retrieve the document's descendants
|
||||||
|
def descendants
|
||||||
|
base_class.where(:parent_ids => self.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns and array of this document and it's descendants
|
||||||
|
#
|
||||||
|
# @return [Array<Mongoid::Document>] Array of the document itself and it's descendants
|
||||||
|
def descendants_and_self
|
||||||
|
[self] + descendants
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Is this document a descendant of the other document?
|
||||||
|
#
|
||||||
|
# @param [Mongoid::Tree] other document to check against
|
||||||
|
#
|
||||||
|
# @return [Boolean] The document is a descendant of the other document
|
||||||
|
def descendant_of?(other)
|
||||||
|
self.parent_ids.include?(other.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns this document's siblings
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Criteria] Mongoid criteria to retrieve the document's siblings
|
||||||
|
def siblings
|
||||||
|
siblings_and_self.excludes(:id => self.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns this document's siblings and itself
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Criteria] Mongoid criteria to retrieve the document's siblings and itself
|
||||||
|
def siblings_and_self
|
||||||
|
base_class.where(:parent_id => self.parent_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Is this document a sibling of the other document?
|
||||||
|
#
|
||||||
|
# @param [Mongoid::Tree] other document to check against
|
||||||
|
#
|
||||||
|
# @return [Boolean] The document is a sibling of the other document
|
||||||
|
def sibling_of?(other)
|
||||||
|
self.parent_id == other.parent_id
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns all leaves of this document (be careful, currently involves two queries)
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Criteria] Mongoid criteria to retrieve the document's leaves
|
||||||
|
def leaves
|
||||||
|
base_class.where(:_id.nin => base_class.only(:parent_id).collect(&:parent_id)).and(:parent_ids => self.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Forces rearranging of all children after next save
|
||||||
|
#
|
||||||
|
# @return [undefined]
|
||||||
|
def rearrange_children!
|
||||||
|
@rearrange_children = true
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Will the children be rearranged after next save?
|
||||||
|
#
|
||||||
|
# @return [Boolean] Whether the children will be rearranged
|
||||||
|
def rearrange_children?
|
||||||
|
!!@rearrange_children
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Nullifies all children's parent_id
|
||||||
|
#
|
||||||
|
# @return [undefined]
|
||||||
|
def nullify_children
|
||||||
|
children.each do |c|
|
||||||
|
c.parent = c.parent_id = nil
|
||||||
|
c.save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Moves all children to this document's parent
|
||||||
|
#
|
||||||
|
# @return [undefined]
|
||||||
|
def move_children_to_parent
|
||||||
|
children.each do |c|
|
||||||
|
c.parent = self.parent
|
||||||
|
c.save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Deletes all descendants using the database (doesn't invoke callbacks)
|
||||||
|
#
|
||||||
|
# @return [undefined]
|
||||||
|
def delete_descendants
|
||||||
|
base_class.delete_all(:conditions => { :parent_ids => self.id })
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Destroys all children by calling their #destroy method (does invoke callbacks)
|
||||||
|
#
|
||||||
|
# @return [undefined]
|
||||||
|
def destroy_children
|
||||||
|
children.destroy_all
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
##
|
||||||
|
# Updates the parent_ids and marks the children for
|
||||||
|
# rearrangement when the parent_ids changed
|
||||||
|
#
|
||||||
|
# @private
|
||||||
|
# @return [undefined]
|
||||||
|
def rearrange
|
||||||
|
if self.parent_id
|
||||||
|
self.parent_ids = parent.parent_ids + [self.parent_id]
|
||||||
|
else
|
||||||
|
self.parent_ids = []
|
||||||
|
end
|
||||||
|
|
||||||
|
self.depth = parent_ids.size
|
||||||
|
|
||||||
|
rearrange_children! if self.parent_ids_changed?
|
||||||
|
end
|
||||||
|
|
||||||
|
def rearrange_children
|
||||||
|
@rearrange_children = false
|
||||||
|
self.children.each { |c| c.save }
|
||||||
|
end
|
||||||
|
|
||||||
|
def position_in_tree
|
||||||
|
errors.add(:parent_id, :invalid) if self.parent_ids.include?(self.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,236 @@
|
||||||
|
module Mongoid
|
||||||
|
module Tree
|
||||||
|
##
|
||||||
|
# = Mongoid::Tree::Ordering
|
||||||
|
#
|
||||||
|
# Mongoid::Tree doesn't order the tree by default. To enable ordering of children
|
||||||
|
# include both Mongoid::Tree and Mongoid::Tree::Ordering into your document.
|
||||||
|
#
|
||||||
|
# == Utility methods
|
||||||
|
#
|
||||||
|
# This module adds methods to get related siblings depending on their position:
|
||||||
|
#
|
||||||
|
# node.lower_siblings
|
||||||
|
# node.higher_siblings
|
||||||
|
# node.first_sibling_in_list
|
||||||
|
# node.last_sibling_in_list
|
||||||
|
#
|
||||||
|
# There are several methods to move nodes around in the list:
|
||||||
|
#
|
||||||
|
# node.move_up
|
||||||
|
# node.move_down
|
||||||
|
# node.move_to_top
|
||||||
|
# node.move_to_bottom
|
||||||
|
# node.move_above(other)
|
||||||
|
# node.move_below(other)
|
||||||
|
#
|
||||||
|
# Additionally there are some methods to check aspects of the document
|
||||||
|
# in the list of children:
|
||||||
|
#
|
||||||
|
# node.at_top?
|
||||||
|
# node.at_bottom?
|
||||||
|
module Ordering
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
field :position, :type => Integer
|
||||||
|
|
||||||
|
default_scope ->{ asc(:position) }
|
||||||
|
|
||||||
|
before_save :assign_default_position, :if => :assign_default_position?
|
||||||
|
before_save :reposition_former_siblings, :if => :sibling_reposition_required?
|
||||||
|
after_destroy :move_lower_siblings_up
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns a chainable criteria for this document's ancestors
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Criteria] Mongoid criteria to retrieve the document's ancestors
|
||||||
|
def ancestors
|
||||||
|
base_class.unscoped { super }
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns siblings below the current document.
|
||||||
|
# Siblings with a position greater than this document's position.
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Criteria] Mongoid criteria to retrieve the document's lower siblings
|
||||||
|
def lower_siblings
|
||||||
|
self.siblings.where(:position.gt => self.position)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns siblings above the current document.
|
||||||
|
# Siblings with a position lower than this document's position.
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Criteria] Mongoid criteria to retrieve the document's higher siblings
|
||||||
|
def higher_siblings
|
||||||
|
self.siblings.where(:position.lt => self.position)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns siblings between the current document and the other document
|
||||||
|
# Siblings with a position between this document's position and the other document's position.
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Criteria] Mongoid criteria to retrieve the documents between this and the other document
|
||||||
|
def siblings_between(other)
|
||||||
|
range = [self.position, other.position].sort
|
||||||
|
self.siblings.where(:position.gt => range.first, :position.lt => range.last)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns the lowest sibling (could be self)
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Document] The lowest sibling
|
||||||
|
def last_sibling_in_list
|
||||||
|
siblings_and_self.last
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns the highest sibling (could be self)
|
||||||
|
#
|
||||||
|
# @return [Mongoid::Document] The highest sibling
|
||||||
|
def first_sibling_in_list
|
||||||
|
siblings_and_self.first
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Is this the highest sibling?
|
||||||
|
#
|
||||||
|
# @return [Boolean] Whether the document is the highest sibling
|
||||||
|
def at_top?
|
||||||
|
higher_siblings.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Is this the lowest sibling?
|
||||||
|
#
|
||||||
|
# @return [Boolean] Whether the document is the lowest sibling
|
||||||
|
def at_bottom?
|
||||||
|
lower_siblings.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Move this node above all its siblings
|
||||||
|
#
|
||||||
|
# @return [undefined]
|
||||||
|
def move_to_top
|
||||||
|
return true if at_top?
|
||||||
|
move_above(first_sibling_in_list)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Move this node below all its siblings
|
||||||
|
#
|
||||||
|
# @return [undefined]
|
||||||
|
def move_to_bottom
|
||||||
|
return true if at_bottom?
|
||||||
|
move_below(last_sibling_in_list)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Move this node one position up
|
||||||
|
#
|
||||||
|
# @return [undefined]
|
||||||
|
def move_up
|
||||||
|
switch_with_sibling_at_offset(-1) unless at_top?
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Move this node one position down
|
||||||
|
#
|
||||||
|
# @return [undefined]
|
||||||
|
def move_down
|
||||||
|
switch_with_sibling_at_offset(1) unless at_bottom?
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Move this node above the specified node
|
||||||
|
#
|
||||||
|
# This method changes the node's parent if nescessary.
|
||||||
|
#
|
||||||
|
# @param [Mongoid::Tree] other document to move this document above
|
||||||
|
#
|
||||||
|
# @return [undefined]
|
||||||
|
def move_above(other)
|
||||||
|
ensure_to_be_sibling_of(other)
|
||||||
|
|
||||||
|
if position > other.position
|
||||||
|
new_position = other.position
|
||||||
|
self.siblings_between(other).inc(:position => 1)
|
||||||
|
other.inc(:position => 1)
|
||||||
|
else
|
||||||
|
new_position = other.position - 1
|
||||||
|
self.siblings_between(other).inc(:position => -1)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.position = new_position
|
||||||
|
save!
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Move this node below the specified node
|
||||||
|
#
|
||||||
|
# This method changes the node's parent if nescessary.
|
||||||
|
#
|
||||||
|
# @param [Mongoid::Tree] other document to move this document below
|
||||||
|
#
|
||||||
|
# @return [undefined]
|
||||||
|
def move_below(other)
|
||||||
|
ensure_to_be_sibling_of(other)
|
||||||
|
|
||||||
|
if position > other.position
|
||||||
|
new_position = other.position + 1
|
||||||
|
self.siblings_between(other).inc(:position => 1)
|
||||||
|
else
|
||||||
|
new_position = other.position
|
||||||
|
self.siblings_between(other).inc(:position => -1)
|
||||||
|
other.inc(:position => -1)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.position = new_position
|
||||||
|
save!
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def switch_with_sibling_at_offset(offset)
|
||||||
|
siblings.where(:position => self.position + offset).first.inc(:position => -offset)
|
||||||
|
inc(:position => offset)
|
||||||
|
end
|
||||||
|
|
||||||
|
def ensure_to_be_sibling_of(other)
|
||||||
|
return if sibling_of?(other)
|
||||||
|
self.parent_id = other.parent_id
|
||||||
|
save!
|
||||||
|
end
|
||||||
|
|
||||||
|
def move_lower_siblings_up
|
||||||
|
lower_siblings.inc(:position => -1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def reposition_former_siblings
|
||||||
|
former_siblings = base_class.where(:parent_id => attribute_was('parent_id')).
|
||||||
|
and(:position.gt => (attribute_was('position') || 0)).
|
||||||
|
excludes(:id => self.id)
|
||||||
|
former_siblings.inc(:position => -1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def sibling_reposition_required?
|
||||||
|
parent_id_changed? && persisted?
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_default_position
|
||||||
|
self.position = if self.siblings.where(:position.ne => nil).any?
|
||||||
|
self.last_sibling_in_list.position + 1
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_default_position?
|
||||||
|
self.position.nil? || self.parent_id_changed?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue