social_stream-base 0.17.3 → 0.18.0
Sign up to get free protection for your applications and to get access to all the features.
- data/app/assets/images/flags/pt.png +0 -0
- data/app/assets/javascripts/social_stream.toolbar.js +41 -0
- data/app/assets/stylesheets/settings.css +1 -0
- data/app/controllers/activity_actions_controller.rb +44 -0
- data/app/controllers/followers_controller.rb +39 -0
- data/app/helpers/activities_helper.rb +10 -10
- data/app/helpers/activity_actions_helper.rb +35 -0
- data/app/helpers/contacts_helper.rb +1 -1
- data/app/helpers/followers_helper.rb +5 -0
- data/app/helpers/toolbar_helper.rb +55 -68
- data/app/models/activity_action.rb +28 -0
- data/app/models/activity_object.rb +11 -2
- data/app/models/actor.rb +23 -33
- data/app/models/contact.rb +32 -43
- data/app/models/group.rb +2 -6
- data/app/models/relation.rb +1 -1
- data/app/models/relation/follow.rb +14 -0
- data/app/models/tie.rb +30 -30
- data/app/models/user.rb +8 -0
- data/app/views/activities/_options.html.erb +0 -1
- data/app/views/activity_actions/_follow_form.html.erb +10 -0
- data/app/views/activity_actions/_follow_sentence.html.erb +3 -0
- data/app/views/activity_actions/_update_form.js.erb +2 -0
- data/app/views/activity_actions/create.js.erb +1 -0
- data/app/views/activity_actions/update.js.erb +1 -0
- data/app/views/avatars/index.html.erb +1 -1
- data/app/views/cheesecake/index.html.erb +1 -1
- data/app/views/contacts/{_link.html.erb → _link_custom.html.erb} +0 -0
- data/app/views/contacts/_link_follow.html.erb +12 -0
- data/app/views/contacts/edit.html.erb +1 -1
- data/app/views/contacts/index.html.erb +1 -1
- data/app/views/contacts/index.js.erb +1 -1
- data/app/views/contacts/new.html.erb +1 -1
- data/app/views/conversations/index.html.erb +1 -1
- data/app/views/conversations/index.js.erb +1 -1
- data/app/views/conversations/show.html.erb +1 -1
- data/app/views/conversations/show.js.erb +1 -1
- data/app/views/devise/registrations/edit.html.erb +1 -1
- data/app/views/followers/destroy.js.erb +1 -0
- data/app/views/followers/index.html.erb +5 -0
- data/app/views/followers/update.js.erb +1 -0
- data/app/views/groups/_show.html.erb +1 -1
- data/app/views/groups/new.html.erb +1 -1
- data/app/views/layouts/_header_dropdown_menu.html.erb +5 -3
- data/app/views/messages/new.html.erb +1 -1
- data/app/views/messages/new.js.erb +1 -1
- data/app/views/objects/_show.html.erb +1 -1
- data/app/views/profiles/edit.html.erb +1 -1
- data/app/views/profiles/show.html.erb +1 -1
- data/app/views/relation/customs/index.html.erb +1 -1
- data/app/views/settings/index.html.erb +1 -1
- data/app/views/settings/index.js.erb +1 -0
- data/app/views/ties/index.html.erb +1 -1
- data/app/views/toolbar/_logo.html.erb +0 -7
- data/app/views/users/_show.html.erb +1 -1
- data/config/locales/en.yml +16 -6
- data/config/locales/es.yml +15 -6
- data/config/locales/pt.yml +507 -0
- data/config/locales/rails.pt.yml +192 -0
- data/config/routes.rb +20 -7
- data/db/migrate/20120316093946_create_activity_actions.rb +15 -0
- data/db/migrate/20120316113728_activity_action_follow.rb +23 -0
- data/lib/generators/social_stream/base/install_generator.rb +0 -4
- data/lib/generators/social_stream/base/templates/initializer.rb +7 -0
- data/lib/inherited_resources/social_stream.rb +18 -0
- data/lib/rails/social_stream.rb +23 -0
- data/lib/social_stream-base.rb +7 -3
- data/lib/social_stream/base/dependencies.rb +3 -2
- data/lib/social_stream/base/engine.rb +6 -6
- data/lib/social_stream/base/version.rb +1 -1
- data/lib/social_stream/models/channeled.rb +8 -0
- data/lib/social_stream/models/object.rb +1 -3
- data/lib/social_stream/models/subtype.rb +31 -25
- data/lib/social_stream/models/supertype.rb +54 -19
- data/lib/social_stream/views/toolbar/base.rb +143 -0
- data/lib/tasks/db/populate.rake +1 -1
- data/social_stream-base.gemspec +1 -3
- data/spec/dummy/config/initializers/social_stream.rb +7 -0
- data/spec/models/activity_action_spec.rb +26 -0
- data/spec/models/tie_spec.rb +2 -2
- metadata +91 -84
- data/app/assets/javascripts/toolbar.js +0 -22
- data/app/views/layouts/_settings.html.erb +0 -18
- data/app/views/toolbar/_home.html.erb +0 -15
- data/app/views/toolbar/_messages.html.erb +0 -15
- data/app/views/toolbar/_profile.html.erb +0 -28
- data/lib/generators/social_stream/base/templates/navigation.rb +0 -4
- data/lib/social_stream/toolbar_config/base.rb +0 -94
Binary file
|
@@ -0,0 +1,41 @@
|
|
1
|
+
SocialStream.Toolbar = (function(SS, $, undefined){
|
2
|
+
var init = function(options){
|
3
|
+
$('.toolbar_menu ul li ul').hide();
|
4
|
+
$('.toolbar_menu li a').click(function() {
|
5
|
+
$(this).next().slideToggle('normal');
|
6
|
+
});
|
7
|
+
|
8
|
+
Menu.init(options);
|
9
|
+
}
|
10
|
+
|
11
|
+
var Menu = (function(SS, $, undefined){
|
12
|
+
var init = function(options){
|
13
|
+
//Logo menu for current subject
|
14
|
+
//Full Caption Sliding (Hidden to Visible)
|
15
|
+
$('.logo_grid.logo_full').hover( function() {
|
16
|
+
$(".logo_menu", this).stop().animate({top:'101px'},{queue:false,duration:160});
|
17
|
+
}, function() {
|
18
|
+
$(".logo_menu", this).stop().animate({top:'1119px'},{queue:false,duration:160});
|
19
|
+
});
|
20
|
+
|
21
|
+
if (options != undefined && options['option'] != undefined && options['option'].length) {
|
22
|
+
expand(options['option']);
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
var expand = function(id) {
|
27
|
+
$('#toolbar_menu-' + id).next().show();
|
28
|
+
}
|
29
|
+
|
30
|
+
return {
|
31
|
+
init: init,
|
32
|
+
expand: expand
|
33
|
+
}
|
34
|
+
})(SS, $)
|
35
|
+
|
36
|
+
return {
|
37
|
+
init: init,
|
38
|
+
expandMenu: Menu.expand
|
39
|
+
}
|
40
|
+
|
41
|
+
})(SocialStream, jQuery);
|
@@ -14,6 +14,7 @@ select#language option {
|
|
14
14
|
select#language option[value=browser] { padding-left: 0; }
|
15
15
|
select#language option[value=en] { background-image: url(flags/en.png); }
|
16
16
|
select#language option[value=es] { background-image: url(flags/es.png); }
|
17
|
+
select#language option[value=pt] { background-image: url(flags/pt.png); }
|
17
18
|
#api_token {
|
18
19
|
font-weight: bold;
|
19
20
|
font-style: italic;
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class ActivityActionsController < ApplicationController
|
2
|
+
# Last tendencies in rails talk about filtering params in the controller,
|
3
|
+
# instead of using attr_protected
|
4
|
+
#
|
5
|
+
# We hope it will be shiped in Rails 4, so we write our custom method for now
|
6
|
+
before_filter :clean_params
|
7
|
+
|
8
|
+
before_filter :can_read_activity_object, :only => :create
|
9
|
+
|
10
|
+
respond_to :js
|
11
|
+
|
12
|
+
def create
|
13
|
+
@activity_action =
|
14
|
+
current_subject.
|
15
|
+
sent_actions.
|
16
|
+
find_or_create_by_activity_object_id @activity_object.id
|
17
|
+
|
18
|
+
@activity_action.update_attributes params[:activity_action]
|
19
|
+
end
|
20
|
+
|
21
|
+
def update
|
22
|
+
activity_action.update_attributes params[:activity_action]
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def clean_params
|
28
|
+
return if params[:activity_action].blank?
|
29
|
+
|
30
|
+
params[:activity_action].delete(:actor_id)
|
31
|
+
params[:activity_action].delete(:activity_object_id) if params[:id].present?
|
32
|
+
end
|
33
|
+
|
34
|
+
def can_read_activity_object
|
35
|
+
@activity_object = ActivityObject.find(params[:activity_action][:activity_object_id])
|
36
|
+
|
37
|
+
authorize! :read, @activity_object.object
|
38
|
+
end
|
39
|
+
|
40
|
+
def activity_action
|
41
|
+
@activity_action ||=
|
42
|
+
current_subject.sent_actions.find params[:id]
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class FollowersController < ApplicationController
|
2
|
+
before_filter :authenticate_user!, :except => :index
|
3
|
+
|
4
|
+
respond_to :html, :js
|
5
|
+
|
6
|
+
def index
|
7
|
+
@contacts =
|
8
|
+
if params[:following]
|
9
|
+
current_subject.sent_contacts
|
10
|
+
else
|
11
|
+
current_subject.received_contacts
|
12
|
+
end
|
13
|
+
|
14
|
+
respond_to do |format|
|
15
|
+
format.html { @contacts = @contacts.page(params[:page]).per(20) }
|
16
|
+
format.js { @contacts = @contacts.page(params[:page]).per(20) }
|
17
|
+
format.json { render :text => to_json(@contacts) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def update
|
22
|
+
current_contact.relation_ids = Array.wrap(Relation::Follow.instance.id)
|
23
|
+
|
24
|
+
respond_to :js
|
25
|
+
end
|
26
|
+
|
27
|
+
def destroy
|
28
|
+
current_contact.relation_ids = Array.new
|
29
|
+
|
30
|
+
respond_to :js
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def current_contact
|
36
|
+
@contact ||=
|
37
|
+
current_subject.sent_contacts.find params[:id]
|
38
|
+
end
|
39
|
+
end
|
@@ -35,22 +35,22 @@ module ActivitiesHelper
|
|
35
35
|
:owner_id => Actor.normalize_id(receiver)
|
36
36
|
end
|
37
37
|
|
38
|
-
def like_sentence(activity)
|
39
|
-
likers_shown
|
40
|
-
likers_count = activity.likes.count
|
41
|
-
likers_other = likers_count - likers_shown
|
38
|
+
def like_sentence(activity, options = {})
|
39
|
+
options[:likers_shown] ||= 2
|
42
40
|
|
43
41
|
# TODO: select likers from current_subject's contacts
|
44
42
|
likers =
|
45
|
-
activity.likes.first(likers_shown).
|
43
|
+
activity.likes.first(options[:likers_shown]).
|
46
44
|
map{ |a| a.sender_subject }.
|
47
|
-
map{ |l| link_to l.name, l }
|
48
|
-
|
45
|
+
map{ |l| link_to l.name, l }
|
46
|
+
|
47
|
+
likers_count = activity.likes.count
|
48
|
+
likers_other = likers_count - options[:likers_shown]
|
49
49
|
|
50
50
|
if likers_other > 0
|
51
|
-
t("
|
52
|
-
else
|
53
|
-
t("activity.like_sentence.few", :likers => likers, :count => likers_count).html_safe
|
51
|
+
likers.push t("activity_action.sentence.more", :count => likers_other)
|
54
52
|
end
|
53
|
+
|
54
|
+
t("activity.like_sentence", :likers => likers.to_sentence, :count => likers_count).html_safe
|
55
55
|
end
|
56
56
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module ActivityActionsHelper
|
2
|
+
def toggle_follow_action(activity_object)
|
3
|
+
action = activity_object.action_from(current_subject)
|
4
|
+
action ||= activity_object.received_actions.build :actor_id => current_subject.actor_id
|
5
|
+
|
6
|
+
action.follow ^= true
|
7
|
+
|
8
|
+
action
|
9
|
+
end
|
10
|
+
|
11
|
+
# Show the {SocialStream::Models::Subject Subjects} that follow
|
12
|
+
# the {ActivityObject object}
|
13
|
+
#
|
14
|
+
# TODO: DRY with ActivitiesHelper#like_sentence
|
15
|
+
def followers_sentence(object, options = {})
|
16
|
+
options[:followers_shown] ||= 2
|
17
|
+
|
18
|
+
followers_count = object.follower_count
|
19
|
+
|
20
|
+
return "" unless followers_count > 0
|
21
|
+
|
22
|
+
followers =
|
23
|
+
object.followers.
|
24
|
+
map{ |a| a.subject }.
|
25
|
+
map{ |l| link_to l.name, l }
|
26
|
+
|
27
|
+
followers_other = followers_count - options[:followers_shown]
|
28
|
+
|
29
|
+
if followers_other > 0
|
30
|
+
followers.push t("activity_action.sentence.more", :count => followers_other)
|
31
|
+
end
|
32
|
+
|
33
|
+
t("#{ object.object_type.underscore }.activity_action.sentence.follow", :followers => followers.to_sentence, :count => followers_count, :default => :"activity_action.sentence.follow").html_safe
|
34
|
+
end
|
35
|
+
end
|
@@ -1,109 +1,96 @@
|
|
1
|
+
# The toolbar is the left-side bar in Social Stream's layout
|
2
|
+
#
|
1
3
|
module ToolbarHelper
|
2
4
|
# Configuration of toolbar items
|
3
|
-
include SocialStream::
|
5
|
+
include SocialStream::Views::Toolbar
|
4
6
|
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# * If present, render the profile menu for the {SocialStream::Models::Subject subject}
|
8
|
-
# * If blank, render the home menu
|
7
|
+
# This method define the toolbar content for your view. The toolbar is at the left
|
8
|
+
# side of the screen in vanilla SocialStream distribution.
|
9
9
|
#
|
10
|
-
# The
|
10
|
+
# The {type} argument chooses diffent configurations. There are three build-in cases:
|
11
|
+
# * :home, render the home menu
|
12
|
+
# * :profile, render the profile menu for the {SocialStream::Models::Subject subject}
|
13
|
+
# this {type} needs a :subject {option} with the subject in the sidebar
|
14
|
+
# * :messages, render the messages menu
|
11
15
|
#
|
12
|
-
#
|
13
|
-
# Autoexpanding a menu section on your view:
|
16
|
+
# Autoexpand a menu section on your view:
|
14
17
|
#
|
15
18
|
# Toolbar allows you to autoexpand certain menu section that may be of interest for your view.
|
16
19
|
# For example, the messages menu when you are looking your inbox. This is done through :option element.
|
17
20
|
#
|
18
|
-
# To get it working, you should use the proper :option to be expanded
|
19
|
-
# mentioned example. This will try
|
20
|
-
# Base toolbar items, automatically, to expand the section of the menu where its root
|
21
|
-
# list link, the one expanding the section, has an id equal to "#messages_menu". If you use
|
21
|
+
# To get it working, you should use the proper :option to be expanded. For instance,
|
22
22
|
# ":options => :contacts" it will try to expand "#contacts_menu".
|
23
23
|
#
|
24
|
-
# For now its working with :option => :messages, :contacts or :groups
|
25
|
-
#
|
26
|
-
#
|
27
24
|
# Examples:
|
28
25
|
#
|
29
26
|
# Render the home toolbar:
|
30
27
|
#
|
31
28
|
# <% toolbar %>
|
32
29
|
#
|
30
|
+
# or
|
31
|
+
#
|
32
|
+
# <% toolbar :home %>
|
33
|
+
#
|
33
34
|
# Render the profile toolbar for a user:
|
34
35
|
#
|
35
|
-
# <% toolbar :profile => @user %>
|
36
|
+
# <% toolbar :profile, :subject => @user %>
|
36
37
|
#
|
37
|
-
# Render the
|
38
|
+
# Render the messages menu:
|
38
39
|
#
|
39
|
-
# <% toolbar :
|
40
|
+
# <% toolbar :messages %>
|
40
41
|
#
|
41
42
|
# Render the profile toolbar for group changing the contacts menu option:
|
42
43
|
#
|
43
|
-
# <% toolbar :profile => @group, :option => :contacts %>
|
44
|
+
# <% toolbar :profile, :subject => @group, :option => :contacts %>
|
44
45
|
#
|
45
|
-
def toolbar(options = {}
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
content = capture do
|
51
|
-
if options[:profile]
|
52
|
-
render :partial => 'toolbar/profile', :locals => { :subject => options[:profile] }
|
53
|
-
elsif options[:option].present? and options[:option].to_s.eql? 'messages'
|
54
|
-
render :partial => 'toolbar/messages'
|
55
|
-
else
|
56
|
-
render :partial => 'toolbar/home'
|
57
|
-
end
|
58
|
-
end
|
46
|
+
def toolbar(type = :home, options = {})
|
47
|
+
content = toolbar_items(type, options).inject(ActiveSupport::SafeBuffer.new){ |result, item|
|
48
|
+
result + item[:html]
|
49
|
+
}
|
59
50
|
|
60
51
|
case request.format
|
61
52
|
when Mime::JS
|
62
53
|
response = <<-EOJ
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
expandSubMenu('#{ options[:option] }');
|
67
|
-
EOJ
|
54
|
+
$('#toolbarContent').html("#{ escape_javascript(content) }");
|
55
|
+
SocialStream.Toolbar.init({ option: '#{ options[:option] }' });
|
56
|
+
EOJ
|
68
57
|
|
69
58
|
response.html_safe
|
70
59
|
else
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
60
|
+
content_for(:toolbar) do
|
61
|
+
content
|
62
|
+
end
|
63
|
+
|
64
|
+
content_for(:javascript) do
|
65
|
+
<<-EOJ
|
66
|
+
SocialStream.Toolbar.init({ option: '#{ options[:option] }' });
|
67
|
+
EOJ
|
68
|
+
end
|
79
69
|
end
|
80
70
|
end
|
81
71
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
def menu_options #:nodoc:
|
86
|
-
@menu_options ||= {}
|
87
|
-
end
|
72
|
+
def toolbar_menu(type, options = {})
|
73
|
+
ActiveSupport::SafeBuffer.new.tap do |menu|
|
74
|
+
menu << '<div class="toolbar_menu">'.html_safe
|
88
75
|
|
89
|
-
|
90
|
-
def home_toolbar_menu
|
91
|
-
render_items home_toolbar_items
|
92
|
-
end
|
76
|
+
toolbar_menu_render(toolbar_menu_items(type, options), menu)
|
93
77
|
|
94
|
-
|
95
|
-
|
96
|
-
render_items profile_toolbar_items(subject)
|
78
|
+
menu << '</div>'.html_safe
|
79
|
+
end
|
97
80
|
end
|
98
81
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
82
|
+
def toolbar_menu_render(items, menu)
|
83
|
+
menu << '<ul>'.html_safe
|
84
|
+
items.each do |item|
|
85
|
+
menu << '<li>'.html_safe
|
86
|
+
|
87
|
+
menu << item[:html]
|
88
|
+
if item[:items].present?
|
89
|
+
toolbar_menu_render(item[:items], menu)
|
90
|
+
end
|
91
|
+
|
92
|
+
menu << '</li>'.html_safe
|
93
|
+
end
|
94
|
+
menu << '</ul>'.html_safe
|
108
95
|
end
|
109
96
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# This model includes all the actions performed by {Actor actors}
|
2
|
+
# on {ActivityObject activity objects}
|
3
|
+
#
|
4
|
+
class ActivityAction < ActiveRecord::Base
|
5
|
+
belongs_to :actor
|
6
|
+
belongs_to :activity_object
|
7
|
+
|
8
|
+
before_save :change_follower_count
|
9
|
+
|
10
|
+
scope :sent_by, lambda{ |actor|
|
11
|
+
where(:actor_id => Actor.normalize_id(actor))
|
12
|
+
}
|
13
|
+
|
14
|
+
scope :received_by, lambda{ |activity_object|
|
15
|
+
where(:activity_object_id => ActivityObject.normalize_id(activity_object))
|
16
|
+
}
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# Updates the follower_count counter in the {ActivityObject}
|
21
|
+
def change_follower_count
|
22
|
+
return unless follow_changed?
|
23
|
+
|
24
|
+
follow? ?
|
25
|
+
activity_object.increment!(:follower_count) :
|
26
|
+
activity_object.decrement!(:follower_count)
|
27
|
+
end
|
28
|
+
end
|
@@ -20,6 +20,14 @@ class ActivityObject < ActiveRecord::Base
|
|
20
20
|
has_many :activity_object_activities, :dependent => :destroy
|
21
21
|
has_many :activities, :through => :activity_object_activities
|
22
22
|
|
23
|
+
has_many :received_actions,
|
24
|
+
:class_name => "ActivityAction",
|
25
|
+
:dependent => :destroy
|
26
|
+
has_many :followers,
|
27
|
+
:through => :received_actions,
|
28
|
+
:source => :actor,
|
29
|
+
:conditions => { 'activity_actions.follow' => true }
|
30
|
+
|
23
31
|
has_many :activity_object_properties,
|
24
32
|
:dependent => :destroy
|
25
33
|
has_many :object_properties,
|
@@ -56,8 +64,9 @@ class ActivityObject < ActiveRecord::Base
|
|
56
64
|
object_type == "Actor"
|
57
65
|
end
|
58
66
|
|
59
|
-
|
60
|
-
|
67
|
+
# Return the {Action} model to an {Actor}
|
68
|
+
def action_from(actor)
|
69
|
+
received_actions.sent_by(actor).first
|
61
70
|
end
|
62
71
|
|
63
72
|
end
|