[issue #347] Added backbone. Changed collaborators page.
This commit is contained in:
parent
851fd9d722
commit
71c8efabf9
2
Gemfile
2
Gemfile
|
@ -44,6 +44,8 @@ gem 'rails3-jquery-autocomplete', '~> 1.0.6'
|
||||||
gem 'will_paginate', '~> 3.0.3'
|
gem 'will_paginate', '~> 3.0.3'
|
||||||
gem 'meta-tags', '~> 1.2.5', :require => 'meta_tags'
|
gem 'meta-tags', '~> 1.2.5', :require => 'meta_tags'
|
||||||
gem "haml-rails", '~> 0.3.4'
|
gem "haml-rails", '~> 0.3.4'
|
||||||
|
gem 'ruby-haml-js'
|
||||||
|
gem 'rails-backbone'
|
||||||
gem 'jquery-rails', '~> 2.0.1'
|
gem 'jquery-rails', '~> 2.0.1'
|
||||||
|
|
||||||
group :assets do
|
group :assets do
|
||||||
|
|
10
Gemfile.lock
10
Gemfile.lock
|
@ -110,6 +110,7 @@ GEM
|
||||||
warden (~> 1.1.1)
|
warden (~> 1.1.1)
|
||||||
diff-display (0.0.1)
|
diff-display (0.0.1)
|
||||||
diff-lcs (1.1.3)
|
diff-lcs (1.1.3)
|
||||||
|
ejs (1.0.0)
|
||||||
erubis (2.7.0)
|
erubis (2.7.0)
|
||||||
eventmachine (0.12.10)
|
eventmachine (0.12.10)
|
||||||
eventmachine (0.12.10-java)
|
eventmachine (0.12.10-java)
|
||||||
|
@ -218,6 +219,10 @@ GEM
|
||||||
activesupport (= 3.2.2)
|
activesupport (= 3.2.2)
|
||||||
bundler (~> 1.0)
|
bundler (~> 1.0)
|
||||||
railties (= 3.2.2)
|
railties (= 3.2.2)
|
||||||
|
rails-backbone (0.7.1)
|
||||||
|
coffee-script (~> 2.2.0)
|
||||||
|
ejs (~> 1.0.0)
|
||||||
|
railties (>= 3.1.0)
|
||||||
rails3-generators (0.17.4)
|
rails3-generators (0.17.4)
|
||||||
railties (>= 3.0.0)
|
railties (>= 3.0.0)
|
||||||
rails3-jquery-autocomplete (1.0.6)
|
rails3-jquery-autocomplete (1.0.6)
|
||||||
|
@ -249,6 +254,9 @@ GEM
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
railties (>= 3.0)
|
railties (>= 3.0)
|
||||||
rspec (~> 2.9.0)
|
rspec (~> 2.9.0)
|
||||||
|
ruby-haml-js (0.0.2)
|
||||||
|
execjs
|
||||||
|
sprockets (>= 2.0.0)
|
||||||
ruby-openid (2.1.8)
|
ruby-openid (2.1.8)
|
||||||
russian (0.6.0)
|
russian (0.6.0)
|
||||||
i18n (>= 0.5.0)
|
i18n (>= 0.5.0)
|
||||||
|
@ -351,6 +359,7 @@ DEPENDENCIES
|
||||||
paperclip (~> 2.7.0)
|
paperclip (~> 2.7.0)
|
||||||
pg (~> 0.13.2)
|
pg (~> 0.13.2)
|
||||||
rails (= 3.2.2)
|
rails (= 3.2.2)
|
||||||
|
rails-backbone
|
||||||
rails3-generators
|
rails3-generators
|
||||||
rails3-jquery-autocomplete (~> 1.0.6)
|
rails3-jquery-autocomplete (~> 1.0.6)
|
||||||
rdiscount
|
rdiscount
|
||||||
|
@ -358,6 +367,7 @@ DEPENDENCIES
|
||||||
redhillonrails_core!
|
redhillonrails_core!
|
||||||
rr (~> 1.0.4)
|
rr (~> 1.0.4)
|
||||||
rspec-rails (~> 2.9.0)
|
rspec-rails (~> 2.9.0)
|
||||||
|
ruby-haml-js
|
||||||
russian (~> 0.6.0)
|
russian (~> 0.6.0)
|
||||||
sass-rails (~> 3.2.5)
|
sass-rails (~> 3.2.5)
|
||||||
shotgun
|
shotgun
|
||||||
|
|
|
@ -6,6 +6,12 @@
|
||||||
//= require jquery.dataTables_ext
|
//= require jquery.dataTables_ext
|
||||||
//= require_tree ./design
|
//= require_tree ./design
|
||||||
//= require_tree ./extra
|
//= require_tree ./extra
|
||||||
|
|
||||||
|
//= require underscore
|
||||||
|
//= require backbone
|
||||||
|
//= require backbone_rails_sync
|
||||||
|
//= require backbone_datalink
|
||||||
|
//= require backbone/rosa
|
||||||
//= require_self
|
//= require_self
|
||||||
|
|
||||||
function disableNotifierCbx(global_cbx) {
|
function disableNotifierCbx(global_cbx) {
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Rosa.bootstrapedData.ROLES = <%= Relation::ROLES.to_json %>;
|
|
@ -0,0 +1,52 @@
|
||||||
|
Rosa.Models.Collaborator = Backbone.Model.extend({
|
||||||
|
paramRoot: 'collaborator',
|
||||||
|
|
||||||
|
defaults: {
|
||||||
|
id: null,
|
||||||
|
name: null,
|
||||||
|
role: null,
|
||||||
|
removed: false
|
||||||
|
},
|
||||||
|
|
||||||
|
changeRole: function(r) {
|
||||||
|
this._prevState = this.get('role');
|
||||||
|
this.save({role: r},
|
||||||
|
{wait: true,
|
||||||
|
error: function(model, response) {
|
||||||
|
model.set({role: model._prevState});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
toggleRemoved: function() {
|
||||||
|
if (this.get('removed') === false) {
|
||||||
|
this.set({removed: true});
|
||||||
|
} else {
|
||||||
|
this.set({removed: false});
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Rosa.Collections.CollaboratorsCollection = Backbone.Collection.extend({
|
||||||
|
model: Rosa.Models.Collaborator,
|
||||||
|
|
||||||
|
initialize: function() {
|
||||||
|
this.url = window.location.pathname;
|
||||||
|
this.on('change:removed add', this.sort, this);
|
||||||
|
},
|
||||||
|
comparator: function(m) {
|
||||||
|
return ((m.get('removed') === true) ? '0' : '1') + m.get('name');
|
||||||
|
},
|
||||||
|
|
||||||
|
removeMarked: function(params) {
|
||||||
|
var marked = this.where({removed: true});
|
||||||
|
if (params['type'] !== undefined) {
|
||||||
|
marked = marked.where({type: params['type']});
|
||||||
|
}
|
||||||
|
marked.forEach(function(el) {
|
||||||
|
el.destroy({wait: true, silent: true});
|
||||||
|
});
|
||||||
|
// this.trigger('reset');
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,15 @@
|
||||||
|
//= require_self
|
||||||
|
//= require ./additionals
|
||||||
|
//= require_tree ./templates
|
||||||
|
//= require_tree ./models
|
||||||
|
//= require_tree ./views
|
||||||
|
//= require_tree ./routers
|
||||||
|
|
||||||
|
window.Rosa = {
|
||||||
|
Models: {},
|
||||||
|
Collections: {},
|
||||||
|
Routers: {},
|
||||||
|
Views: {},
|
||||||
|
|
||||||
|
bootstrapedData: {}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
Rosa.Routers.CollaboratorsRouter = Backbone.Router.extend({
|
||||||
|
routes: {},
|
||||||
|
|
||||||
|
initialize: function() {
|
||||||
|
this.collaboratorsCollection = new Rosa.Collections.CollaboratorsCollection(Rosa.bootstrapedData.collaborators);
|
||||||
|
this.usersView = new Rosa.Views.CollaboratorsView({collection_type: 'user', collection: this.collaboratorsCollection});
|
||||||
|
this.groupsView = new Rosa.Views.CollaboratorsView({collection_type: 'group', collection: this.collaboratorsCollection});
|
||||||
|
|
||||||
|
this.usersView.render();
|
||||||
|
this.groupsView.render();
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,38 @@
|
||||||
|
%td
|
||||||
|
%span#niceCheckbox1.nicecheck-main{ style: "background-position: 0px 0px; "}
|
||||||
|
- if (removed === true) {
|
||||||
|
%input{ type: 'checkbox', value: 1, id: type + '_remove_' + id + '_', name: type + '_remove[' + id + '][]', checked: 'checked' }
|
||||||
|
- } else {
|
||||||
|
%input{ type: 'checkbox', value: 1, id: type + '_remove_' + id + '_', name: type + '_remove[' + id + '][]' }
|
||||||
|
- }
|
||||||
|
%td
|
||||||
|
- if (type === 'user') {
|
||||||
|
.img
|
||||||
|
%img{src: avatar, alt: avatar}
|
||||||
|
- }
|
||||||
|
.forimg
|
||||||
|
%a{href: collaborator_link}
|
||||||
|
= name
|
||||||
|
- var ROLES = Rosa.bootstrapedData.ROLES;
|
||||||
|
- for (var i = 0; i < ROLES.length; i++) {
|
||||||
|
%td
|
||||||
|
.radio
|
||||||
|
- var radio_id = type + '_' + id + '_' + ROLES[i];
|
||||||
|
- var radio_type = type + '[' + id + ']';
|
||||||
|
- if (ROLES[i] === role) {
|
||||||
|
- if ( removed ) {
|
||||||
|
%input.niceRadio{type: 'radio', value: ROLES[i], id: radio_id, name: radio_type, disabled: 'disabled', checked: 'checked'}
|
||||||
|
- } else {
|
||||||
|
%input.niceRadio{type: 'radio', value: ROLES[i], id: radio_id, name: radio_type, checked: 'checked'}
|
||||||
|
- };
|
||||||
|
- } else {
|
||||||
|
- if ( removed ) {
|
||||||
|
%input.niceRadio{type: 'radio', value: ROLES[i], id: radio_id, name: radio_type, disabled: 'disabled' }
|
||||||
|
- } else {
|
||||||
|
%input.niceRadio{type: 'radio', value: ROLES[i], id: radio_id, name: radio_type }
|
||||||
|
- };
|
||||||
|
- }
|
||||||
|
.forradio
|
||||||
|
%label{for: radio_id}
|
||||||
|
= ROLES[i]
|
||||||
|
- }
|
|
@ -0,0 +1,39 @@
|
||||||
|
Rosa.Views.CollaboratorView = Backbone.View.extend({
|
||||||
|
template: JST['backbone/templates/collaborators/collaborator'],
|
||||||
|
tagName: 'tr',
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'change input[type="radio"]': 'changeRole',
|
||||||
|
'change input[type="checkbox"]': 'toggleRemoved'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function() {
|
||||||
|
this.$el.attr('id', 'admin-table-members-row' + this.options.model.get('id') + this.options.model.get('type'));
|
||||||
|
this.model.on('change', this.render, this);
|
||||||
|
this.model.on('destroy', this.hide, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
if (this.model.get('removed')) {
|
||||||
|
this.$el.addClass('removed');
|
||||||
|
} else {
|
||||||
|
this.$el.removeClass('removed');
|
||||||
|
};
|
||||||
|
this.$el.html(this.template(this.model.toJSON()));
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
changeRole: function(e) {
|
||||||
|
this.model.changeRole(e.target.value);
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleRemoved: function(e) {
|
||||||
|
//var mod = this.model
|
||||||
|
//this.$el.addClass('removed').fadeOut(1000, function() { mod.toggleRemoved() });
|
||||||
|
this.model.toggleRemoved();
|
||||||
|
},
|
||||||
|
|
||||||
|
hide: function() {
|
||||||
|
this.remove();
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,38 @@
|
||||||
|
Rosa.Views.CollaboratorsView = Backbone.View.extend({
|
||||||
|
initialize: function() {
|
||||||
|
this._type = this.options['collection_type'];
|
||||||
|
this.setupDeleter();
|
||||||
|
this.$el = $('#' + this._type + 's_collaborators > tbody');
|
||||||
|
this.collection.on('add', this.addOne, this);
|
||||||
|
this.collection.on('reset', this.render, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
addOne: function(collaborator) {
|
||||||
|
if (collaborator.get('type') === this._type) {
|
||||||
|
var cView = new Rosa.Views.CollaboratorView({ model: collaborator });
|
||||||
|
this.$el.append(cView.render().el);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
this.$el.empty();
|
||||||
|
var col = new Rosa.Collections.CollaboratorsCollection(this.collection.where({type: this._type}));
|
||||||
|
col.forEach(this.addOne, this);
|
||||||
|
if (col.where({ removed: true }).length > 0) {
|
||||||
|
this._$deleter.show();
|
||||||
|
} else {
|
||||||
|
this._$deleter.hide();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
setupDeleter: function() {
|
||||||
|
this._$deleter = $('#' + this._type + 's_deleter');
|
||||||
|
this._$deleter.on('click.deleter', '', {context: this}, this.deleterClick);
|
||||||
|
this._$deleter.attr('title', 'Remove selected rows');
|
||||||
|
},
|
||||||
|
|
||||||
|
deleterClick: function(e) {
|
||||||
|
e.data['context'].collection.removeMarked({type: this._type});
|
||||||
|
}
|
||||||
|
});
|
|
@ -76,7 +76,9 @@ function changeRadioStart(el) {
|
||||||
}
|
}
|
||||||
|
|
||||||
el.next().bind("mousedown", function(e) {
|
el.next().bind("mousedown", function(e) {
|
||||||
changeRadio($(this));
|
if (e.which === 0) {
|
||||||
|
changeRadio($(this));
|
||||||
|
};
|
||||||
$(this).find("input:radio").change();
|
$(this).find("input:radio").change();
|
||||||
});
|
});
|
||||||
if($.browser.msie) {
|
if($.browser.msie) {
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
// PUT custom styles here ONLY
|
// PUT custom styles here ONLY
|
||||||
|
|
||||||
span.error {
|
span.error, .hidden {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.centered {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
a#manage-labels {
|
a#manage-labels {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
@ -456,10 +460,12 @@ table.tablesorter tr td.buttons {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.tablesorter tr td.buttons a span.delete {
|
table.tablesorter tr td.buttons a span.delete,
|
||||||
|
span.delete {
|
||||||
background: image-url('x.png') no-repeat 0 0 transparent;
|
background: image-url('x.png') no-repeat 0 0 transparent;
|
||||||
width: 12px;
|
width: 12px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#fork-and-edit {display:block;}
|
#fork-and-edit {display:block;}
|
||||||
|
@ -764,3 +770,7 @@ div.tos_sidebar ul li a {
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.tablesorter tbody tr.removed td {
|
||||||
|
background-color: #FFECEC;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# -*- encoding : utf-8 -*-
|
# -*- encoding : utf-8 -*-
|
||||||
class CollaboratorsController < ApplicationController
|
class CollaboratorsController < ApplicationController
|
||||||
|
respond_to :html, :json
|
||||||
|
|
||||||
before_filter :authenticate_user!
|
before_filter :authenticate_user!
|
||||||
|
|
||||||
before_filter :find_project
|
before_filter :find_project
|
||||||
|
@ -10,7 +12,9 @@ class CollaboratorsController < ApplicationController
|
||||||
before_filter :authorize_collaborators
|
before_filter :authorize_collaborators
|
||||||
|
|
||||||
def index
|
def index
|
||||||
redirect_to edit_project_collaborators_path(@project)
|
# redirect_to edit_project_collaborators_path(@project)
|
||||||
|
@collaborators = Collaborator.find_by_project(@project)
|
||||||
|
respond_with @collaborators
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
@ -30,38 +34,44 @@ class CollaboratorsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
params['user'].keys.each { |user_id|
|
@c = Collaborator.new(params[:collaborator])
|
||||||
role = params['user'][user_id]
|
if @c.save
|
||||||
|
respond_with @c
|
||||||
if relation = @project.relations.find_by_object_id_and_object_type(user_id, 'User')
|
|
||||||
unless @project.owner_type == 'User' and @project.owner_id.to_i == user_id.to_i
|
|
||||||
relation.update_attribute(:role, role)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
relation = @project.relations.build(:object_id => user_id, :object_type => 'User', :role => role)
|
|
||||||
relation.save
|
|
||||||
end
|
|
||||||
} if params['user']
|
|
||||||
|
|
||||||
params['group'].keys.each { |group_id|
|
|
||||||
role = params['group'][group_id]
|
|
||||||
if relation = @project.relations.find_by_object_id_and_object_type(group_id, 'Group')
|
|
||||||
unless @project.owner_type == 'Group' and @project.owner_id.to_i == group_id.to_i
|
|
||||||
relation.update_attribute(:role, role)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
relation = @project.relations.build(:object_id => user_id, :object_type => 'Group', :role => role)
|
|
||||||
relation.save
|
|
||||||
end
|
|
||||||
} if params['group']
|
|
||||||
|
|
||||||
if @project.save
|
|
||||||
flash[:notice] = t("flash.collaborators.successfully_changed")
|
|
||||||
else
|
else
|
||||||
flash[:error] = t("flash.collaborators.error_in_changing")
|
raise
|
||||||
end
|
end
|
||||||
|
# params['user'].keys.each { |user_id|
|
||||||
redirect_to edit_project_collaborators_path(@project)
|
# role = params['user'][user_id]
|
||||||
|
#
|
||||||
|
# if relation = @project.relations.find_by_object_id_and_object_type(user_id, 'User')
|
||||||
|
# unless @project.owner_type == 'User' and @project.owner_id.to_i == user_id.to_i
|
||||||
|
# relation.update_attribute(:role, role)
|
||||||
|
# end
|
||||||
|
# else
|
||||||
|
# relation = @project.relations.build(:object_id => user_id, :object_type => 'User', :role => role)
|
||||||
|
# relation.save
|
||||||
|
# end
|
||||||
|
# } if params['user']
|
||||||
|
#
|
||||||
|
# params['group'].keys.each { |group_id|
|
||||||
|
# role = params['group'][group_id]
|
||||||
|
# if relation = @project.relations.find_by_object_id_and_object_type(group_id, 'Group')
|
||||||
|
# unless @project.owner_type == 'Group' and @project.owner_id.to_i == group_id.to_i
|
||||||
|
# relation.update_attribute(:role, role)
|
||||||
|
# end
|
||||||
|
# else
|
||||||
|
# relation = @project.relations.build(:object_id => user_id, :object_type => 'Group', :role => role)
|
||||||
|
# relation.save
|
||||||
|
# end
|
||||||
|
# } if params['group']
|
||||||
|
#
|
||||||
|
# if @project.save
|
||||||
|
# flash[:notice] = t("flash.collaborators.successfully_changed")
|
||||||
|
# else
|
||||||
|
# flash[:error] = t("flash.collaborators.error_in_changing")
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# redirect_to edit_project_collaborators_path(@project)
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove
|
def remove
|
||||||
|
@ -88,6 +98,12 @@ class CollaboratorsController < ApplicationController
|
||||||
redirect_to edit_project_collaborators_path(@project) + "##{params['user_remove'].present? ? 'users' : 'groups'}"
|
redirect_to edit_project_collaborators_path(@project) + "##{params['user_remove'].present? ? 'users' : 'groups'}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@cb = Collaborator.find_by_project(@project, :id => params[:id])
|
||||||
|
@cb.destroy if @cb
|
||||||
|
respond_with @cb
|
||||||
|
end
|
||||||
|
|
||||||
def add
|
def add
|
||||||
# TODO: Here is used Chelyabinsk method to display Flash messages.
|
# TODO: Here is used Chelyabinsk method to display Flash messages.
|
||||||
|
|
||||||
|
@ -120,7 +136,7 @@ class CollaboratorsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
# if add an anchor, adding will be more pleasant, but flash message wouldn't be shown.
|
# if add an anchor, adding will be more pleasant, but flash message wouldn't be shown.
|
||||||
redirect_to edit_project_collaborators_path(@project) # + "##{(params['member_id'].present?) ? 'users' : 'groups'}"
|
redirect_to project_collaborators_path(@project) # + "##{(params['member_id'].present?) ? 'users' : 'groups'}"
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
|
@ -30,4 +30,8 @@ module ProjectsHelper
|
||||||
def alone_member?(project)
|
def alone_member?(project)
|
||||||
Relation.by_target(project).by_object(current_user).size > 0
|
Relation.by_target(project).by_object(current_user).size > 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def participant_path(participant)
|
||||||
|
participant.kind_of?(User) ? user_path(participant) : group_path(participant)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
# -*- encoding : utf-8 -*-
|
||||||
|
class Collaborator
|
||||||
|
include ActiveModel::Conversion
|
||||||
|
include ActiveModel::Validations
|
||||||
|
include ActiveModel::Serializers::JSON
|
||||||
|
include ActiveModel::MassAssignmentSecurity
|
||||||
|
|
||||||
|
attr_accessor :role, :actor, :project
|
||||||
|
attr_reader :id, :type, :name, :project_id
|
||||||
|
|
||||||
|
attr_accessible :role
|
||||||
|
|
||||||
|
delegate :new_record?, :to => :relation
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def find_by_project(project, opts = {})
|
||||||
|
(id, type) = if opts[:id].present?
|
||||||
|
if opts[:type].present?
|
||||||
|
[opts[:id], opts[:type]]
|
||||||
|
else
|
||||||
|
opts[:id].split('-', 2)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
[nil, nil]
|
||||||
|
end
|
||||||
|
puts id
|
||||||
|
puts type
|
||||||
|
if id.present? and type.present?
|
||||||
|
rel = project.relations.where(:object_id => id, :object_type => type.classify).first
|
||||||
|
puts rel.inspect
|
||||||
|
res = from_relation(project.relations.where(:object_id => id, :object_type => type.classify).first)
|
||||||
|
else
|
||||||
|
res = []
|
||||||
|
project.relations.each do |r|
|
||||||
|
res << from_relation(r) unless project.owner_id == r.object_id and project.owner_type == r.object_type
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
def from_relation(relation)
|
||||||
|
return self.new(:relation => relation, :id => relation.object_id,
|
||||||
|
:type => relation.object_type, :project_id => relation.target_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(args = {})
|
||||||
|
args.to_options!
|
||||||
|
acc_options = args.select{ |(k, v)| k.in? [:actor, :project] }
|
||||||
|
acc_options.each_pair do |name, value|
|
||||||
|
send("#{name}=", value)
|
||||||
|
end
|
||||||
|
|
||||||
|
if @project.nil? and args[:project_id].present?
|
||||||
|
@project = Project.find(args[:project_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
if @actor.nil? and args[:type].present? and args[:id].present?
|
||||||
|
@actor = args[:type].classify.constantize.find(args[:id].to_s.split('-', 2).first.to_i) rescue nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if args[:relation]
|
||||||
|
@relation = args[:relation]
|
||||||
|
else
|
||||||
|
setup_relation
|
||||||
|
end
|
||||||
|
|
||||||
|
@relation.role = args[:role] if args[:role]
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_attributes(attributes, options = {})
|
||||||
|
sanitize_for_mass_assignment(attributes, options[:as]).each_pair do |k, v|
|
||||||
|
send("#{k}=", v)
|
||||||
|
end
|
||||||
|
save
|
||||||
|
end
|
||||||
|
|
||||||
|
def actor=(model)
|
||||||
|
@actor = model
|
||||||
|
|
||||||
|
setup_relation
|
||||||
|
end
|
||||||
|
|
||||||
|
def project=(model)
|
||||||
|
@project = model
|
||||||
|
|
||||||
|
setup_relation
|
||||||
|
end
|
||||||
|
|
||||||
|
def id
|
||||||
|
@actor.try(:id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
@actor.class.to_s.underscore
|
||||||
|
end
|
||||||
|
|
||||||
|
def name
|
||||||
|
if @actor.present?
|
||||||
|
@actor.instance_of?(User) ? "#{@actor.uname} (#{@actor.name})" : @actor.uname
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def project_id
|
||||||
|
@project.try(:id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def role
|
||||||
|
@relation.role
|
||||||
|
end
|
||||||
|
|
||||||
|
def role=(arg)
|
||||||
|
@relation.role = arg
|
||||||
|
end
|
||||||
|
|
||||||
|
def save
|
||||||
|
@relation.try(:save)
|
||||||
|
end
|
||||||
|
|
||||||
|
def save!
|
||||||
|
@relation.try(:save!)
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@relation.try(:destroy)
|
||||||
|
end
|
||||||
|
|
||||||
|
def attributes
|
||||||
|
%w{ id type name project_id role}.inject({}) do |h, e|
|
||||||
|
h.merge(e => send(e))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def persisted?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def relation
|
||||||
|
setup_relation
|
||||||
|
@relation
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup_relation
|
||||||
|
if @actor.present? and @project.present?
|
||||||
|
@relation = Relation.by_object(@actor).by_target(@project).limit(1).first
|
||||||
|
@relation ||= Relation.new(:object_id => @actor.id, :object_type => @actor.class.to_s.underscore,
|
||||||
|
:target_id => @project.id, :target_type => 'Project')
|
||||||
|
else
|
||||||
|
@relation = Relation.new
|
||||||
|
@relation.object = @actor
|
||||||
|
@relation.target = @project
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
Collaborator.include_root_in_json = false
|
|
@ -0,0 +1,5 @@
|
||||||
|
json.id collaborator.id.to_s + '-' + collaborator.type
|
||||||
|
json.name collaborator.name
|
||||||
|
json.type collaborator.type
|
||||||
|
json.project_id collaborator.project_id
|
||||||
|
json.role collaborator.role
|
|
@ -0,0 +1,9 @@
|
||||||
|
json.array!(collaborators) do |json, cb|
|
||||||
|
json.id cb.id.to_s + '-' + cb.type
|
||||||
|
json.name cb.name
|
||||||
|
json.collaborator_link participant_path(cb.actor)
|
||||||
|
json.avatar avatar_url(cb.actor) if cb.actor.kind_of?(User)
|
||||||
|
json.type cb.type
|
||||||
|
json.project_id cb.project_id
|
||||||
|
json.role cb.role
|
||||||
|
end
|
|
@ -0,0 +1,100 @@
|
||||||
|
-set_meta_tags :title => [title_object(@project), t('layout.projects.members')]
|
||||||
|
= render :partial => 'projects/sidebar'
|
||||||
|
= render :partial => 'projects/submenu'
|
||||||
|
|
||||||
|
%a{:name => 'users'}
|
||||||
|
%h3= t("layout.users.list_header")
|
||||||
|
|
||||||
|
= form_tag add_project_collaborators_path(@project) do
|
||||||
|
.admin-search
|
||||||
|
= autocomplete_field_tag 'member_id', params[:member_id], autocomplete_user_uname_users_path, :id_element => '#member_id_field'
|
||||||
|
.admin-role
|
||||||
|
.lineForm
|
||||||
|
= select_tag 'role', options_for_collaborators_roles_select
|
||||||
|
= hidden_field_tag 'member_id', nil, :id => 'member_id_field'
|
||||||
|
= submit_tag t("layout.add"), :class => 'button'
|
||||||
|
.both
|
||||||
|
|
||||||
|
= form_tag project_collaborators_path(@project), :id => 'members_form', :delete_url => remove_project_collaborators_path(@project) do
|
||||||
|
= hidden_field_tag "_method", "post"
|
||||||
|
%table#users_collaborators.tablesorter{:cellpadding => "0", :cellspacing => "0"}
|
||||||
|
%thead
|
||||||
|
%tr
|
||||||
|
%th.centered
|
||||||
|
%span#users_deleter.hidden
|
||||||
|
%span.delete
|
||||||
|
%th
|
||||||
|
= t("layout.collaborators.members")
|
||||||
|
%th{:colspan => "3"}
|
||||||
|
= t("layout.collaborators.roles")
|
||||||
|
%tbody
|
||||||
|
-# @users.each_with_index do |user, num|
|
||||||
|
%tr{:id => "admin-table-members-row#{num}"}
|
||||||
|
%td
|
||||||
|
%span#niceCheckbox1.niceCheck-main{ :style => "background-position: 0px 0px; "}
|
||||||
|
= check_box_tag "user_remove[#{user.id}][]"
|
||||||
|
%td
|
||||||
|
.img
|
||||||
|
= image_tag avatar_url(user)
|
||||||
|
.forimg= link_to "#{user.uname} (#{user.name})", user_path(user)
|
||||||
|
- Relation::ROLES.each_with_index do |role, i|
|
||||||
|
%td
|
||||||
|
.radio
|
||||||
|
= radio_button_tag "user[#{user.id}]", role, ((@project.relations.exists? :object_id => user.id, :object_type => 'User', :role => role) ? :checked : nil), :class => 'niceRadio'
|
||||||
|
.forradio= t("layout.collaborators.role_names.#{ role }")
|
||||||
|
=# link_to_function t("layout.delete_selected"), "deleteAdminMember();", :class => 'button'
|
||||||
|
=# link_to_function t("layout.save"), "saveAdminMember();", :class => 'button right_floated'
|
||||||
|
.both
|
||||||
|
%br
|
||||||
|
|
||||||
|
.hr.bottom
|
||||||
|
.both
|
||||||
|
|
||||||
|
%a{:name => 'groups'}
|
||||||
|
%h3= t("layout.groups.list_header")
|
||||||
|
|
||||||
|
= form_tag add_project_collaborators_path(@project) do
|
||||||
|
.admin-search
|
||||||
|
= autocomplete_field_tag 'group_id', params[:group_id], autocomplete_group_uname_groups_path, :id_element => '#group_id_field'
|
||||||
|
.admin-role
|
||||||
|
.lineForm
|
||||||
|
= select_tag 'role', options_for_collaborators_roles_select, :id => 'group_role'
|
||||||
|
= hidden_field_tag 'group_id', nil, :id => 'group_id_field'
|
||||||
|
= submit_tag t("layout.add"), :class => 'button'
|
||||||
|
.both
|
||||||
|
|
||||||
|
= form_tag project_collaborators_path(@project), :id => 'groups_form', :delete_url => remove_project_collaborators_path(@project) do
|
||||||
|
= hidden_field_tag "_method", "post", :id => 'groups_method'
|
||||||
|
%table#groups_collaborators.tablesorter{:cellpadding => "0", :cellspacing => "0"}
|
||||||
|
%thead
|
||||||
|
%tr
|
||||||
|
%th.centered
|
||||||
|
%span#groups_deleter.hidden
|
||||||
|
%span.delete
|
||||||
|
%th
|
||||||
|
= t("layout.collaborators.members")
|
||||||
|
%th{:colspan => "3"}
|
||||||
|
= t("layout.collaborators.roles")
|
||||||
|
%tbody
|
||||||
|
-# @groups.each_with_index do |group, num|
|
||||||
|
%tr{:id => "admin-table-members-row#{num + @users.size + 1}"}
|
||||||
|
%td
|
||||||
|
%span#niceCheckbox1.niceCheck-main{ :style => "background-position: 0px 0px; "}
|
||||||
|
= check_box_tag "group_remove[#{group.id}][]"
|
||||||
|
%td
|
||||||
|
.forimg= link_to "#{group.uname}", group_path(group)
|
||||||
|
- Relation::ROLES.each_with_index do |role, i|
|
||||||
|
%td
|
||||||
|
.radio
|
||||||
|
= radio_button_tag "group[#{group.id}]", role, ((@project.relations.exists? :object_id => group.id, :object_type => 'Group', :role => role) ? :checked : nil), :class => 'niceRadio'
|
||||||
|
.forradio= t("layout.collaborators.role_names.#{ role }")
|
||||||
|
=# link_to_function t("layout.delete_selected"), "deleteAdminGroup();", :class => 'button'
|
||||||
|
=# link_to_function t("layout.save"), "saveAdminGroup();", :class => 'button right_floated'
|
||||||
|
.both
|
||||||
|
.both
|
||||||
|
|
||||||
|
:javascript
|
||||||
|
$(function() {
|
||||||
|
Rosa.bootstrapedData.collaborators = #{ render :partial => 'collaborators.json.jbuilder', :locals => {:collaborators => @collaborators } };
|
||||||
|
var r = new Rosa.Routers.CollaboratorsRouter();
|
||||||
|
});
|
|
@ -0,0 +1 @@
|
||||||
|
json.partial! 'collaborators', :collaborators => @collaborators
|
|
@ -33,7 +33,7 @@ Rosa::Application.configure do
|
||||||
config.assets.compress = false
|
config.assets.compress = false
|
||||||
|
|
||||||
# Expands the lines which load the assets
|
# Expands the lines which load the assets
|
||||||
config.assets.debug = false
|
config.assets.debug = true
|
||||||
|
|
||||||
# Raise exception on mass assignment protection for Active Record models
|
# Raise exception on mass assignment protection for Active Record models
|
||||||
config.active_record.mass_assignment_sanitizer = :strict
|
config.active_record.mass_assignment_sanitizer = :strict
|
||||||
|
|
|
@ -110,7 +110,7 @@ Rosa::Application.routes.draw do
|
||||||
resources :build_lists, :only => [:index, :new, :create] do
|
resources :build_lists, :only => [:index, :new, :create] do
|
||||||
collection { post :search }
|
collection { post :search }
|
||||||
end
|
end
|
||||||
resources :collaborators, :only => [:index, :edit, :update, :add] do
|
resources :collaborators, :only => [:index, :edit, :update, :add, :destroy] do
|
||||||
collection do
|
collection do
|
||||||
get :edit
|
get :edit
|
||||||
post :update
|
post :update
|
||||||
|
|
Loading…
Reference in New Issue