diff --git a/Gemfile b/Gemfile index a8d3c9714..a11e9337c 100644 --- a/Gemfile +++ b/Gemfile @@ -44,6 +44,8 @@ gem 'rails3-jquery-autocomplete', '~> 1.0.6' gem 'will_paginate', '~> 3.0.3' gem 'meta-tags', '~> 1.2.5', :require => 'meta_tags' gem "haml-rails", '~> 0.3.4' +gem 'ruby-haml-js' +gem 'rails-backbone' gem 'jquery-rails', '~> 2.0.1' group :assets do diff --git a/Gemfile.lock b/Gemfile.lock index 893a65ef5..786cb8c3c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -110,6 +110,7 @@ GEM warden (~> 1.1.1) diff-display (0.0.1) diff-lcs (1.1.3) + ejs (1.0.0) erubis (2.7.0) eventmachine (0.12.10) eventmachine (0.12.10-java) @@ -218,6 +219,10 @@ GEM activesupport (= 3.2.2) bundler (~> 1.0) 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) railties (>= 3.0.0) rails3-jquery-autocomplete (1.0.6) @@ -249,6 +254,9 @@ GEM activesupport (>= 3.0) railties (>= 3.0) rspec (~> 2.9.0) + ruby-haml-js (0.0.2) + execjs + sprockets (>= 2.0.0) ruby-openid (2.1.8) russian (0.6.0) i18n (>= 0.5.0) @@ -351,6 +359,7 @@ DEPENDENCIES paperclip (~> 2.7.0) pg (~> 0.13.2) rails (= 3.2.2) + rails-backbone rails3-generators rails3-jquery-autocomplete (~> 1.0.6) rdiscount @@ -358,6 +367,7 @@ DEPENDENCIES redhillonrails_core! rr (~> 1.0.4) rspec-rails (~> 2.9.0) + ruby-haml-js russian (~> 0.6.0) sass-rails (~> 3.2.5) shotgun diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index d8dd4c4fe..d588204ad 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -6,6 +6,12 @@ //= require jquery.dataTables_ext //= require_tree ./design //= require_tree ./extra + +//= require underscore +//= require backbone +//= require backbone_rails_sync +//= require backbone_datalink +//= require backbone/rosa //= require_self function disableNotifierCbx(global_cbx) { diff --git a/app/assets/javascripts/backbone/additionals.js.erb b/app/assets/javascripts/backbone/additionals.js.erb new file mode 100644 index 000000000..36cd3700a --- /dev/null +++ b/app/assets/javascripts/backbone/additionals.js.erb @@ -0,0 +1 @@ +Rosa.bootstrapedData.ROLES = <%= Relation::ROLES.to_json %>; diff --git a/app/assets/javascripts/backbone/models/.gitkeep b/app/assets/javascripts/backbone/models/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/app/assets/javascripts/backbone/models/collaborator.js b/app/assets/javascripts/backbone/models/collaborator.js new file mode 100644 index 000000000..c9cff44f4 --- /dev/null +++ b/app/assets/javascripts/backbone/models/collaborator.js @@ -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'); + } +}); diff --git a/app/assets/javascripts/backbone/rosa.js b/app/assets/javascripts/backbone/rosa.js new file mode 100644 index 000000000..9ed5f3096 --- /dev/null +++ b/app/assets/javascripts/backbone/rosa.js @@ -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: {} +} diff --git a/app/assets/javascripts/backbone/routers/.gitkeep b/app/assets/javascripts/backbone/routers/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/app/assets/javascripts/backbone/routers/collaborators_router.js b/app/assets/javascripts/backbone/routers/collaborators_router.js new file mode 100644 index 000000000..252d22961 --- /dev/null +++ b/app/assets/javascripts/backbone/routers/collaborators_router.js @@ -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(); + } +}); diff --git a/app/assets/javascripts/backbone/templates/.gitkeep b/app/assets/javascripts/backbone/templates/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/app/assets/javascripts/backbone/templates/collaborators/collaborator.jst.hamljs b/app/assets/javascripts/backbone/templates/collaborators/collaborator.jst.hamljs new file mode 100644 index 000000000..4a3ed14d2 --- /dev/null +++ b/app/assets/javascripts/backbone/templates/collaborators/collaborator.jst.hamljs @@ -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] +- } diff --git a/app/assets/javascripts/backbone/views/.gitkeep b/app/assets/javascripts/backbone/views/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/app/assets/javascripts/backbone/views/collaborator_view.js b/app/assets/javascripts/backbone/views/collaborator_view.js new file mode 100644 index 000000000..6bec2c3f4 --- /dev/null +++ b/app/assets/javascripts/backbone/views/collaborator_view.js @@ -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(); + } +}); diff --git a/app/assets/javascripts/backbone/views/collaborators_view.js b/app/assets/javascripts/backbone/views/collaborators_view.js new file mode 100644 index 000000000..a6955e44b --- /dev/null +++ b/app/assets/javascripts/backbone/views/collaborators_view.js @@ -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}); + } +}); diff --git a/app/assets/javascripts/design/radio.js b/app/assets/javascripts/design/radio.js index 179027de2..01f13bbca 100644 --- a/app/assets/javascripts/design/radio.js +++ b/app/assets/javascripts/design/radio.js @@ -76,7 +76,9 @@ function changeRadioStart(el) { } el.next().bind("mousedown", function(e) { - changeRadio($(this)); + if (e.which === 0) { + changeRadio($(this)); + }; $(this).find("input:radio").change(); }); if($.browser.msie) { diff --git a/app/assets/stylesheets/design/custom.scss b/app/assets/stylesheets/design/custom.scss index 90d49db25..4fc960eda 100644 --- a/app/assets/stylesheets/design/custom.scss +++ b/app/assets/stylesheets/design/custom.scss @@ -1,9 +1,13 @@ // PUT custom styles here ONLY -span.error { +span.error, .hidden { display: none; } +.centered { + text-align: center; +} + a#manage-labels { margin-bottom: 10px; } @@ -456,10 +460,12 @@ table.tablesorter tr td.buttons { 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; width: 12px; display: inline-block; + cursor: pointer; } #fork-and-edit {display:block;} @@ -764,3 +770,7 @@ div.tos_sidebar ul li a { padding-top: 5px; text-decoration: none; } + +table.tablesorter tbody tr.removed td { + background-color: #FFECEC; +} diff --git a/app/controllers/collaborators_controller.rb b/app/controllers/collaborators_controller.rb index ac237350a..1272ffe36 100644 --- a/app/controllers/collaborators_controller.rb +++ b/app/controllers/collaborators_controller.rb @@ -1,5 +1,7 @@ # -*- encoding : utf-8 -*- class CollaboratorsController < ApplicationController + respond_to :html, :json + before_filter :authenticate_user! before_filter :find_project @@ -10,7 +12,9 @@ class CollaboratorsController < ApplicationController before_filter :authorize_collaborators 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 def show @@ -30,38 +34,44 @@ class CollaboratorsController < ApplicationController end def update - params['user'].keys.each { |user_id| - 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") + @c = Collaborator.new(params[:collaborator]) + if @c.save + respond_with @c else - flash[:error] = t("flash.collaborators.error_in_changing") + raise end - - redirect_to edit_project_collaborators_path(@project) +# params['user'].keys.each { |user_id| +# 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 def remove @@ -88,6 +98,12 @@ class CollaboratorsController < ApplicationController redirect_to edit_project_collaborators_path(@project) + "##{params['user_remove'].present? ? 'users' : 'groups'}" end + def destroy + @cb = Collaborator.find_by_project(@project, :id => params[:id]) + @cb.destroy if @cb + respond_with @cb + end + def add # TODO: Here is used Chelyabinsk method to display Flash messages. @@ -120,7 +136,7 @@ class CollaboratorsController < ApplicationController end # 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 protected diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 11472533c..653b5fa9b 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -30,4 +30,8 @@ module ProjectsHelper def alone_member?(project) Relation.by_target(project).by_object(current_user).size > 0 end + + def participant_path(participant) + participant.kind_of?(User) ? user_path(participant) : group_path(participant) + end end diff --git a/app/models/collaborator.rb b/app/models/collaborator.rb new file mode 100644 index 000000000..729349be9 --- /dev/null +++ b/app/models/collaborator.rb @@ -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 diff --git a/app/views/collaborators/_collaborator.json.jbuilder b/app/views/collaborators/_collaborator.json.jbuilder new file mode 100644 index 000000000..579523e7a --- /dev/null +++ b/app/views/collaborators/_collaborator.json.jbuilder @@ -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 diff --git a/app/views/collaborators/_collaborators.json.jbuilder b/app/views/collaborators/_collaborators.json.jbuilder new file mode 100644 index 000000000..85b5259fa --- /dev/null +++ b/app/views/collaborators/_collaborators.json.jbuilder @@ -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 diff --git a/app/views/collaborators/index.html.haml b/app/views/collaborators/index.html.haml new file mode 100644 index 000000000..41a780110 --- /dev/null +++ b/app/views/collaborators/index.html.haml @@ -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(); + }); diff --git a/app/views/collaborators/index.json.jbuilder b/app/views/collaborators/index.json.jbuilder new file mode 100644 index 000000000..259ed6bc4 --- /dev/null +++ b/app/views/collaborators/index.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'collaborators', :collaborators => @collaborators diff --git a/config/environments/development.rb b/config/environments/development.rb index 3b763e0c3..890a1ec7f 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -33,7 +33,7 @@ Rosa::Application.configure do config.assets.compress = false # 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 config.active_record.mass_assignment_sanitizer = :strict diff --git a/config/routes.rb b/config/routes.rb index c1fbe84b1..83fe9d5ec 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -110,7 +110,7 @@ Rosa::Application.routes.draw do resources :build_lists, :only => [:index, :new, :create] do collection { post :search } end - resources :collaborators, :only => [:index, :edit, :update, :add] do + resources :collaborators, :only => [:index, :edit, :update, :add, :destroy] do collection do get :edit post :update