Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

News feed #81

Merged
merged 9 commits into from
Sep 26, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion app/assets/javascripts/base.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ componentBuilder = (name, container) ->
"#{name}:#{_id}"

start: ->
if not components[name]?
console?.error "Component not found: #{name}"
return
console?.log "Starting Component: #{name}"
_comp = components[name]()
_comp.container = container
_comp.identifier = @compId()
Expand Down Expand Up @@ -66,7 +70,10 @@ componentsManager = (container) ->
@onStarted()

startComponents = (evt, root=document) ->
$(root).find('[data-components]').each (i, container) =>
attr = 'data-components'
$root = $ root
componentsManager($root).buildComponents() if $root.attr(attr)
$root.find("[#{attr}]").each (i, container) =>
componentsManager($(container)).buildComponents()

mediator.subscribe 'components:start', startComponents
Expand Down
96 changes: 96 additions & 0 deletions app/assets/javascripts/components/selector.js.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
App.components.selector = ->
initialize: ->
@baseURL = @attr.url ? "#{window.location.pathname}"
@getQueryValues()
@getParams()
@updateValues()
@bindEvents()
@updateDisplay()

getQueryValues: ->
@queryValues = _.reduce(window.location.search.substr(1).split('&'), (ret, param) ->
parts = param.replace(/\+/g, ' ').split('=')
key = decodeURIComponent(parts[0])
val = parts[1]
val = if not val? then null else decodeURIComponent(val)
if not ret[key]?
ret[key] = val
else if _.isArray ret[key]
ret[key].push val
else
ret[key] = [ret[key], val]
return ret
, {})

getParams: ->
selectors = $(".options")
@params ?= {}
for selector in selectors
selector = $ selector
paramName = selector.data "selector-param"
defaultValue = selector.find('.option[data-selector-default]').data "selector-value"
@params[paramName] ?=
name: paramName
selector: selector
default: defaultValue
value: @queryValues[paramName]
@params

updateValue: (param) ->
value = param.value ? param.default
selectedOption = param.selector.find(".option").filter ->
$(this).data("selector-selected") is true
value = selectedOption.data "selector-value" if selectedOption.length > 0
param.value = value

updateValues: ->
for paramName, param of @params
@updateValue param

updateDisplay: ->
for paramName, param of @params
param.selector.find(".option").each (idx, el) ->
el = $ el
selected = el.data("selector-value") is param.value
el.data "selector-selected", selected
if not selected then el.removeClass("selected") else el.addClass("selected")

changeValue: (param, value) ->
return if param.value is value
param.value = value
App.mediator.publish "selector:changed", @getURLParams()
@loadURL() if @attr.autoload
@updateDisplay()

bindEvents: ->
that = this
for paramName, param of @params
param.selector.find(".option").click ((param) ->
(evt) ->
evt.preventDefault()
value = $(this).data "selector-value"
that.changeValue param, value
)(param)

onSuccess: (data) ->
content = $(data).find(@attr.target)
$(@attr.target).replaceWith content
App.mediator.publish "components:start", content
App.utils.spinner.hide()

getURLParams: ->
params = {}
for paramName, param of @params
params[paramName] = param.value if param.value?
params

getURL: ->
params = $.param @getURLParams()
"#{@baseURL}?#{params}#{window.location.hash}"

loadURL: ->
App.utils.spinner.show()
if @attr.remote
$.get @getURL(), @onSuccess.bind(this)
else
window.location = @getURL()
16 changes: 15 additions & 1 deletion app/assets/stylesheets/activities.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
}
}

.event-owner,
.event-type {
font-weight: bold;
}

.activity-event {
display: inline-block;
display: inline;
}

.activity-time {
Expand All @@ -34,6 +35,19 @@
margin-left: 10px;
}

.owner-avatar {
display: inline-block;
float: left;
margin: -3px 6px 0 -22px;
position: relative;

img {
border: $white 1px solid;
width: 22px;
height: 22px;
}
}

.activity-changes {
margin-top: 5px;
font-size: 0.9em;
Expand Down
15 changes: 12 additions & 3 deletions app/assets/stylesheets/pages/_frontpage.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@
h3{ text-indent: 5px; }
}

li {
.blog li {
:hover { background: $meppit-light-blue; }
a {
display: block;
Expand All @@ -162,10 +162,19 @@
img { margin-right: 0.2em }
}

.last_updates .updates {
.last_updates {
margin: 0;

li a { margin-bottom: 0; }
#activity {
height: 310px;
overflow-y: auto;
}

.activities-list {
.list-item {
&.small .item { width: 350px; }
}
}
}

.apart {
Expand Down
7 changes: 5 additions & 2 deletions app/assets/stylesheets/shared/_export.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@

.help { margin-top: 20px;}

.option {
width: 89.5px;
.options {
width: 100%;
.option {
width: 25%;
}
}
}
#export-help {
Expand Down
78 changes: 59 additions & 19 deletions app/assets/stylesheets/shared/_options.css.scss
Original file line number Diff line number Diff line change
@@ -1,21 +1,61 @@
.option {
display: inline-block;
cursor: pointer;
text-align: center;
margin: 0 5px;
padding: 20px 0;
font-size: 1.2em;
font-weight: bold;
text-decoration: none;
color: white;
background-color: $meppit-dark-blue;
border-radius: 5px;
border: solid 1px $meppit-data-color;

&:first-child { margin-left: 0;}
&:last-child { margin-right: 0;}

&:hover {
background-color: lighten($meppit-dark-blue, 10%);
.options {
display: table;
min-height: 60px;
border-spacing: 5px;

.option {
display: table-cell;
cursor: pointer;
text-align: center;
margin: 0 5px;
padding: 5px;
font-size: 1.2em;
font-weight: bold;
text-decoration: none;
color: white;
background-color: $meppit-dark-blue;
border-radius: 5px;
border: solid 1px $meppit-data-color;
vertical-align: middle;

&:first-child { margin-left: 0;}
&:last-child { margin-right: 0;}

&:hover {
background-color: lighten($meppit-dark-blue, 10%);
border: solid 1px $meppit-data-color;
}
}
}

.selector {
margin: 10px 0;

.options-label {
font-weight: bold;
}

.options-label,
.options-container {
display: inline-block;
vertical-align: middle;
}

.options {
min-height: 40px;

.option {
color: $medium-grey;
background-color: $ultra-soft-grey;
border: solid 1px $soft-grey;
font-weight: normal;
padding: 10px;

&.selected {
color: $white;
background-color: $meppit-dark-blue;
border: solid 1px $meppit-data-color;
}
}
}
}
6 changes: 6 additions & 0 deletions app/controllers/activities_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ def user_activity
render layout: nil if request.xhr?
end

def news_feed
all = (params[:display] == 'all')
@activities = news_feed_results all
render layout: nil if request.xhr?
end

private

def find_user
Expand Down
9 changes: 9 additions & 0 deletions app/controllers/concerns/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,14 @@ def flash_xhr(msg)
flash.now[:notice] = msg
render_to_string(partial: 'shared/alerts')
end

def news_feed_results(all=false)
if all || !current_user
activities = paginate PublicActivity::Activity.order('created_at desc').includes(:trackable, :owner)
else
activities = paginate current_user.following_activities.includes(:owner)
end
activities
end
end

1 change: 1 addition & 0 deletions app/controllers/pages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

class PagesController < ApplicationController
def frontpage
@activities = news_feed_results
@news = news
end

Expand Down
7 changes: 7 additions & 0 deletions app/helpers/concerns/components_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ def autocomplete_field_tag(name, url)
render('shared/components/autocomplete', name: name, url: url).html_safe
end

def selector_option(label, param, value, default=false, class_name=nil)
class_name = value unless class_name
selected = params[param] == value.to_s || (params[param].nil? && default)
"<a href=\"?#{param}=#{value}\" class=\"option #{class_name}#{' selected' if selected}\" data-selector-param=\"#{param}\" data-selector-value=\"#{value}\" #{'data-selector-default="true"' if default}>#{label}</a>".html_safe

end

def additional_info_value(f)
dict = f.object.additional_info
(dict && !dict.empty?) ? dict.to_yaml.gsub("---\n", "") : ""
Expand Down
34 changes: 34 additions & 0 deletions app/models/concerns/follower.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,39 @@ def unfollow(obj)
def follow?(obj)
followings.where(followable: obj).exists?
end

def following_activities
activities = PublicActivity::Activity.arel_table
followings = Following.arel_table
sql = activities.join(followings).on(
# we want activities related to objetcs followed by this user
# AND activities owned by users followed by this user
followings[:followable_type].in([activities[:trackable_type], activities[:owner_type]])
).where(
# Activities from objects followed by this user
Arel::Nodes::Grouping.new(
activities[:trackable_id].eq(followings[:followable_id]).and(
activities[:trackable_type].eq(followings[:followable_type])
)
).or(
# Activities owned by users followed by this user
Arel::Nodes::Grouping.new(
activities[:owner_id].eq(followings[:followable_id]).and(
followings[:followable_type].eq(self.class.name)
)
)
).and(
# Only followed by this user
followings[:follower_id].eq(self.id)
).and(
# But remove activities owned by this user itself
activities[:owner_type].eq(self.class.name).and(
activities[:owner_id].not_eq(self.id))
)
).project('activities.id')
# Convert to ActiveRecord Relation
PublicActivity::Activity.includes(:trackable).where(
activities[:id].in(sql)).order("activities.created_at desc")
end
end
end
2 changes: 1 addition & 1 deletion app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def geojson_properties
end

def activities_performed
PublicActivity::Activity.where(owner: self).includes(:trackable, :owner).order('created_at desc')
PublicActivity::Activity.where(owner: self).includes(:trackable).order('created_at desc')
end

def notifications
Expand Down
Loading