diff --git a/Changelog.md b/Changelog.md
index 6cbeeacc0..ccaa87b4e 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -13,6 +13,7 @@
* Remove the hack for loading the entire lib folder with a proper solution. [#3809](https://github.com/diaspora/diaspora/issues/3750)
* Update and refactor the default public view `public/default.html` [#3811](https://github.com/diaspora/diaspora/issues/3811)
* Write unicorn stderr and stdout [#3785](https://github.com/diaspora/diaspora/pull/3785)
+* Ported aspects to backbone [#3850](https://github.com/diaspora/diaspora/pull/3850)
## Features
diff --git a/app/assets/javascripts/app/collections/aspects.js b/app/assets/javascripts/app/collections/aspects.js
new file mode 100644
index 000000000..33c9cb56c
--- /dev/null
+++ b/app/assets/javascripts/app/collections/aspects.js
@@ -0,0 +1,26 @@
+app.collections.Aspects = Backbone.Collection.extend({
+ model: app.models.Aspect,
+
+ selectedAspects: function(attribute){
+ return _.pluck(_.filter(this.toJSON(), function(a){
+ return a.selected;
+ }), attribute);
+ },
+
+ allSelected: function(){
+ return this.length === _.filter(this.toJSON(), function(a){ return a.selected; }).length;
+ },
+
+ selectAll: function(){
+ this.map(function(a){ a.set({ 'selected' : true })} );
+ },
+
+ deselectAll: function(){
+ this.map(function(a){ a.set({ 'selected' : false })} );
+ },
+
+ toSentence: function(){
+ var separator = Diaspora.I18n.t("comma") + ' ';
+ return this.selectedAspects('name').join(separator).replace(/,\s([^,]+)$/, ' ' + Diaspora.I18n.t("and") + ' $1') || Diaspora.I18n.t("my_aspects");
+ }
+})
diff --git a/app/assets/javascripts/app/models/aspect.js b/app/assets/javascripts/app/models/aspect.js
new file mode 100644
index 000000000..8ae6dac71
--- /dev/null
+++ b/app/assets/javascripts/app/models/aspect.js
@@ -0,0 +1,5 @@
+app.models.Aspect = Backbone.Model.extend({
+ toggleSelected: function(){
+ this.set({'selected' : !this.get('selected')});
+ }
+});
diff --git a/app/assets/javascripts/app/models/stream_aspects.js b/app/assets/javascripts/app/models/stream_aspects.js
new file mode 100644
index 000000000..f8536c65d
--- /dev/null
+++ b/app/assets/javascripts/app/models/stream_aspects.js
@@ -0,0 +1,27 @@
+app.models.StreamAspects = app.models.Stream.extend({
+
+ url : function(){
+ return _.any(this.items.models) ? this.timeFilteredPath() : this.basePath()
+ },
+
+ initialize : function(models, options){
+ var collectionClass = options && options.collection || app.collections.Posts;
+ this.items = new collectionClass([], this.collectionOptions());
+ this.aspects_ids = options.aspects_ids;
+ },
+
+ basePath : function(){
+ return '/aspects';
+ },
+
+ fetch: function() {
+ if(this.isFetching()){ return false }
+ var url = this.url();
+ var ids = this.aspects_ids;
+ this.deferred = this.items.fetch({
+ add : true,
+ url : url,
+ data : { 'a_ids': ids }
+ }).done(_.bind(this.triggerFetchedEvents, this))
+ }
+});
diff --git a/app/assets/javascripts/app/router.js b/app/assets/javascripts/app/router.js
index 6fcd6c95b..f1aa32b95 100644
--- a/app/assets/javascripts/app/router.js
+++ b/app/assets/javascripts/app/router.js
@@ -11,8 +11,8 @@ app.Router = Backbone.Router.extend({
"stream": "stream",
"participate": "stream",
"explore": "stream",
- "aspects": "stream",
- "aspects:query": "stream",
+ "aspects": "aspects",
+ "aspects/stream": "aspects_stream",
"commented": "stream",
"liked": "stream",
"mentions": "stream",
@@ -74,13 +74,36 @@ app.Router = Backbone.Router.extend({
followedTagsView.setupAutoSuggest();
app.tagFollowings.add(preloads.tagFollowings);
-
+
if(name) {
var followedTagsAction = new app.views.TagFollowingAction(
{tagText: name}
);
$("#author_info").prepend(followedTagsAction.render().el)
}
+ },
+
+ aspects : function(){
+ app.aspects = new app.collections.Aspects(app.currentUser.get('aspects'));
+ var aspects_list = new app.views.AspectsList({ collection: app.aspects });
+ aspects_list.render();
+ this.aspects_stream();
+ },
+
+ aspects_stream : function(){
+
+ var ids = app.aspects.selectedAspects('id');
+ app.stream = new app.models.StreamAspects([], { aspects_ids: ids });
+ app.stream.fetch();
+
+ app.page = new app.views.Stream({model : app.stream});
+ app.publisher = app.publisher || new app.views.Publisher({collection : app.stream.items});
+ app.publisher.updateAspectsSelector(ids);
+
+ var streamFacesView = new app.views.StreamFaces({collection : app.stream.items});
+
+ $("#main_stream").html(app.page.render().el);
+ $('#selected_aspect_contacts .content').html(streamFacesView.render().el);
}
});
diff --git a/app/assets/javascripts/app/views/aspect_view.js b/app/assets/javascripts/app/views/aspect_view.js
new file mode 100644
index 000000000..67d15429a
--- /dev/null
+++ b/app/assets/javascripts/app/views/aspect_view.js
@@ -0,0 +1,28 @@
+app.views.Aspect = app.views.Base.extend({
+ templateName: "aspect",
+
+ tagName: "li",
+
+ initialize: function(){
+ if (this.model.get('selected')){
+ this.$el.addClass('active');
+ };
+ },
+
+ events: {
+ 'click a.aspect_selector': 'toggleAspect'
+ },
+
+ toggleAspect: function(evt){
+ if (evt) { evt.preventDefault(); };
+ this.$el.toggleClass('active');
+ this.model.toggleSelected();
+ app.router.aspects_stream();
+ },
+
+ presenter : function() {
+ return _.extend(this.defaultPresenter(), {
+ aspect : this.model
+ })
+ }
+});
diff --git a/app/assets/javascripts/app/views/aspects_list_view.js b/app/assets/javascripts/app/views/aspects_list_view.js
new file mode 100644
index 000000000..468a79b8a
--- /dev/null
+++ b/app/assets/javascripts/app/views/aspects_list_view.js
@@ -0,0 +1,55 @@
+app.views.AspectsList = app.views.Base.extend({
+ templateName: 'aspects-list',
+
+ el: '#aspects_list',
+
+ events: {
+ 'click .toggle_selector' : 'toggleAll'
+ },
+
+ initialize: function(){
+ this.collection.on('change', this.toggleSelector, this);
+ this.collection.on('change', this.updateStreamTitle, this);
+ },
+
+ postRenderTemplate: function() {
+ this.collection.each(this.appendAspect, this);
+ this.$('a[rel*=facebox]').facebox();
+ this.updateStreamTitle();
+ this.toggleSelector();
+ },
+
+ appendAspect: function(aspect) {
+ $("#aspects_list > *:last").before(new app.views.Aspect({
+ model: aspect, attributes: {'data-aspect_id': aspect.get('id')}
+ }).render().el);
+ },
+
+ toggleAll: function(evt){
+ if (evt) { evt.preventDefault(); };
+
+ if (this.collection.allSelected()) {
+ this.collection.deselectAll();
+ this.$('li:not(:last)').removeClass("active");
+ } else {
+ this.collection.selectAll();
+ this.$('li:not(:last)').addClass("active");
+ }
+
+ this.toggleSelector();
+ app.router.aspects_stream();
+ },
+
+ toggleSelector: function(){
+ var selector = this.$('a.toggle_selector');
+ if (this.collection.allSelected()) {
+ selector.text(Diaspora.I18n.t('aspect_navigation.deselect_all'));
+ } else {
+ selector.text(Diaspora.I18n.t('aspect_navigation.select_all'));
+ }
+ },
+
+ updateStreamTitle: function(){
+ $('.stream_title').text(this.collection.toSentence());
+ }
+})
diff --git a/app/assets/javascripts/app/views/publisher/aspects_selector.js b/app/assets/javascripts/app/views/publisher/aspects_selector.js
index ecb2c5764..d3b364265 100644
--- a/app/assets/javascripts/app/views/publisher/aspects_selector.js
+++ b/app/assets/javascripts/app/views/publisher/aspects_selector.js
@@ -21,16 +21,28 @@
}
// update the selection summary
- AspectsDropdown.updateNumber(
- el.closest(".dropdown_list"),
- null,
- el.parent().find('li.selected').length,
- ''
- );
+ this._updateAspectsNumber(el);
this._updateSelectedAspectIds();
},
+ updateAspectsSelector: function(ids){
+ var el = this.$("ul.dropdown_list");
+ this.$('.dropdown_list > li').each(function(){
+ var el = $(this);
+ var aspectId = el.data('aspect_id');
+ if (_.contains(ids, aspectId)) {
+ el.addClass('selected');
+ }
+ else {
+ el.removeClass('selected');
+ }
+ });
+
+ this._updateAspectsNumber(el);
+ this._updateSelectedAspectIds();
+ },
+
// take care of the form fields that will indicate the selected aspects
_updateSelectedAspectIds: function() {
var self = this;
@@ -52,6 +64,15 @@
});
},
+ _updateAspectsNumber: function(el){
+ AspectsDropdown.updateNumber(
+ el.closest(".dropdown_list"),
+ null,
+ el.parent().find('li.selected').length,
+ ''
+ );
+ },
+
_addHiddenAspectInput: function(id) {
var uid = _.uniqueId('aspect_ids_');
this.$('.content_creation form').append(
@@ -59,4 +80,4 @@
);
}
};
-})();
\ No newline at end of file
+})();
diff --git a/app/assets/javascripts/pages/streams-aspects.js b/app/assets/javascripts/pages/streams-aspects.js
deleted file mode 100644
index 6b85b63a2..000000000
--- a/app/assets/javascripts/pages/streams-aspects.js
+++ /dev/null
@@ -1,7 +0,0 @@
-Diaspora.Pages.StreamsAspects = function() {
- var self = this;
-
- this.subscribe("page/ready", function(evt, document) {
- self.aspectNavigation = self.instantiate("AspectNavigation", document.find("ul#aspect_nav"));
- });
-};
diff --git a/app/assets/javascripts/widgets/aspect-navigation.js b/app/assets/javascripts/widgets/aspect-navigation.js
deleted file mode 100644
index a6e9d095a..000000000
--- a/app/assets/javascripts/widgets/aspect-navigation.js
+++ /dev/null
@@ -1,98 +0,0 @@
-/* Copyright (c) 2010, Diaspora Inc. This file is
- * licensed under the Affero General Public License version 3 or later. See
- * the COPYRIGHT file.
- */
-
-(function() {
- Diaspora.Widgets.AspectNavigation = function() {
- var self = this;
-
- this.subscribe("widget/ready", function(evt, aspectNavigation) {
- $.extend(self, {
- aspectNavigation: aspectNavigation,
- aspectSelectors: aspectNavigation.find("a.aspect_selector[data-guid]"),
- aspectLis: aspectNavigation.find("li[data-aspect_id]"),
- toggleSelector: aspectNavigation.find("a.toggle_selector")
- });
-
- self.aspectSelectors.click(self.toggleAspect);
- self.toggleSelector.click(self.toggleAll);
- });
-
- this.selectedAspects = function() {
- return self.aspectNavigation.find("li.active[data-aspect_id]").map(function() { return $(this).data('aspect_id') });
- };
-
- this.toggleAspect = function(evt) {
- evt.preventDefault();
-
- $(this).parent().toggleClass("active");
- self.perform();
- };
-
- this.toggleAll = function(evt) {
- evt.preventDefault();
-
- if (self.allSelected()) {
- self.aspectLis.removeClass("active");
- } else {
- self.aspectLis.addClass("active");
- }
- self.perform();
- };
-
- this.perform = function() {
- if (self.noneSelected()) {
- // clear the posts
- app.page.collection.reset();
- app.page.render();
-
- // toggle the button
- this.calculateToggleText();
- return;
- } else {
- window.location = self.generateURL(); // hella hax
- }
- };
-
- this.calculateToggleText = function() {
- if (self.allSelected()) {
- self.toggleSelector.text(Diaspora.I18n.t('aspect_navigation.deselect_all'));
- } else {
- self.toggleSelector.text(Diaspora.I18n.t('aspect_navigation.select_all'));
- }
- };
-
- this.generateURL = function() {
- var baseURL = 'aspects';
-
- // generate new url
- baseURL = baseURL.replace('#','');
- baseURL += '?';
-
- self.aspectLis.each(function() {
- var aspectLi = $(this);
- if (aspectLi.hasClass("active")) {
- baseURL += "a_ids[]=" + aspectLi.data("aspect_id") + "&";
- }
- });
-
- if(!$("#publisher").hasClass("closed")) {
- // open publisher
- baseURL += "op=true";
- } else {
- // slice last '&'
- baseURL = baseURL.slice(0,baseURL.length-1);
- }
- return baseURL;
- };
-
- this.noneSelected = function() {
- return self.aspectLis.filter(".active").length === 0;
- }
-
- this.allSelected = function() {
- return self.aspectLis.not(".active").length === 0;
- }
- };
-})();
diff --git a/app/assets/templates/aspect_tpl.jst.hbs b/app/assets/templates/aspect_tpl.jst.hbs
new file mode 100644
index 000000000..5e51e1bed
--- /dev/null
+++ b/app/assets/templates/aspect_tpl.jst.hbs
@@ -0,0 +1,6 @@
+
+ {{name}}
diff --git a/app/assets/templates/aspects-list_tpl.jst.hbs b/app/assets/templates/aspects-list_tpl.jst.hbs
new file mode 100644
index 000000000..493f259a4
--- /dev/null
+++ b/app/assets/templates/aspects-list_tpl.jst.hbs
@@ -0,0 +1,6 @@
+
+ {{ t "aspect_navigation.select_all" }}
+
+
+ {{ t "aspect_navigation.add_an_aspect" }}
+
diff --git a/app/controllers/streams_controller.rb b/app/controllers/streams_controller.rb
index 4d6f2852c..a4e300823 100644
--- a/app/controllers/streams_controller.rb
+++ b/app/controllers/streams_controller.rb
@@ -21,7 +21,7 @@ class StreamsController < ApplicationController
:json
def aspects
- aspect_ids = (session[:a_ids] ? session[:a_ids] : [])
+ aspect_ids = (session[:a_ids] || [])
@stream = Stream::Aspect.new(current_user, aspect_ids,
:max_time => max_time)
stream_responder
diff --git a/app/helpers/layout_helper.rb b/app/helpers/layout_helper.rb
index 781fa5679..c226aff74 100644
--- a/app/helpers/layout_helper.rb
+++ b/app/helpers/layout_helper.rb
@@ -39,7 +39,8 @@ module LayoutHelper
def set_current_user_in_javascript
return unless user_signed_in?
- user = UserPresenter.new(current_user).to_json
+ a_ids = session[:a_ids] || []
+ user = UserPresenter.new(current_user, a_ids).to_json
content_tag(:script) do
<<-JS.html_safe
window.current_user_attributes = #{user}
diff --git a/app/presenters/user_presenter.rb b/app/presenters/user_presenter.rb
index 018b57187..1874570c4 100644
--- a/app/presenters/user_presenter.rb
+++ b/app/presenters/user_presenter.rb
@@ -1,8 +1,9 @@
class UserPresenter
- attr_accessor :user
+ attr_accessor :user, :aspects_ids
- def initialize(user)
- self.user = user
+ def initialize(user, aspects_ids)
+ self.user = user
+ self.aspects_ids = aspects_ids
end
def to_json(options = {})
@@ -27,7 +28,11 @@ class UserPresenter
end
def aspects
- AspectPresenter.as_collection(user.aspects)
+ @aspects ||= begin
+ aspects = AspectPresenter.as_collection(user.aspects)
+ no_aspects = self.aspects_ids.empty?
+ aspects.each{ |a| a[:selected] = no_aspects || self.aspects_ids.include?(a[:id].to_s) }
+ end
end
def notifications_count
diff --git a/app/views/aspects/_aspect_listings.haml b/app/views/aspects/_aspect_listings.haml
index 41659509f..8e593df9d 100644
--- a/app/views/aspects/_aspect_listings.haml
+++ b/app/views/aspects/_aspect_listings.haml
@@ -4,19 +4,6 @@
%ul#aspect_nav.left_nav.sub
%li.all_aspects
- = link_to t('streams.aspects.title'), aspects_path, :class => 'home_selector'
+ = link_to t('streams.aspects.title'), aspects_path, :class => 'home_selector', :rel => 'backbone'
- - if @stream.is_a?(Stream::Aspect)
- %ul.sub_nav
- - if defined?(stream)
- %a.toggle_selector{:href => '#'}
- = stream.for_all_aspects? ? t('.deselect_all') : t('.select_all')
- - for aspect in all_aspects
- %li{:data => {:aspect_id => aspect.id}, :class => ("active" if defined?(stream) && stream.aspect_ids.include?(aspect.id))}
- .edit
- = link_to image_tag("icons/pencil.png", :title => t('.edit_aspect', :name => aspect.name)), edit_aspect_path(aspect), :rel => "facebox"
- %a.aspect_selector{:href => aspects_path("a_ids[]" => aspect.id), :class => "name", 'data-guid' => aspect.id}
- = aspect
-
- %li
- = link_to t('.add_an_aspect'), new_aspect_path, :class => "new_aspect", :rel => "facebox"
+ %ul#aspects_list.sub_nav
diff --git a/app/views/aspects/_aspect_stream.haml b/app/views/aspects/_aspect_stream.haml
index ca9263159..7b6121685 100644
--- a/app/views/aspects/_aspect_stream.haml
+++ b/app/views/aspects/_aspect_stream.haml
@@ -5,7 +5,7 @@
%h3#aspect_stream_header.stream_title
= stream.title
- = render 'shared/publisher', :selected_aspects => stream.aspects, :aspect_ids => stream.aspect_ids, :for_all_aspects => stream.for_all_aspects?, :aspect => stream.aspect
+= render 'shared/publisher', :selected_aspects => stream.aspects, :aspect_ids => stream.aspect_ids, :for_all_aspects => stream.for_all_aspects?, :aspect => stream.aspect
= render 'aspects/no_posts_message'
#gs-shim{:title => popover_with_close_html("3. #{t('.stay_updated')}"), 'data-content' => t('.stay_updated_explanation')}
diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml
index 0811598d5..83e95433e 100644
--- a/config/locales/javascript/javascript.en.yml
+++ b/config/locales/javascript/javascript.en.yml
@@ -9,6 +9,9 @@ en:
delete: "Delete"
ignore: "Ignore"
ignore_user: "Ignore this user?"
+ and: "and"
+ comma: ","
+ edit: "Edit"
timeago:
prefixAgo: ""
prefixFromNow: ""
@@ -28,6 +31,7 @@ en:
my_activity: "My Activity"
my_stream: "Stream"
+ my_aspects: "My Aspects"
videos:
watch: "Watch this video on <%= provider %>"
@@ -64,6 +68,7 @@ en:
select_all: "Select all"
deselect_all: "Deselect all"
no_aspects: "No aspects selected"
+ add_an_aspect: "+ Add an aspect"
getting_started:
hey: "Hey, <%= name %>!"
no_tags: "Hey, you haven't followed any tags! Continue anyway?"
diff --git a/features/oembed.feature b/features/oembed.feature
index 3777c1fc3..9ae7a2b44 100644
--- a/features/oembed.feature
+++ b/features/oembed.feature
@@ -17,6 +17,7 @@ Feature: oembed
When I fill in the following:
| status_message_fake_text | http://youtube.com/watch?v=M3r2XDceM6A&format=json |
And I press "Share"
+ And I wait for the ajax to finish
And I follow "My Aspects"
Then I should see a video player
And I should see a ".oembed" within ".post-content"
diff --git a/spec/javascripts/app/collections/aspects_spec.js b/spec/javascripts/app/collections/aspects_spec.js
new file mode 100644
index 000000000..786cec3d6
--- /dev/null
+++ b/spec/javascripts/app/collections/aspects_spec.js
@@ -0,0 +1,94 @@
+describe("app.collections.Aspects", function(){
+ beforeEach(function(){
+ Diaspora.I18n.loadLocale({
+ 'and' : "and",
+ 'comma' : ",",
+ 'my_aspects' : "My Aspects"
+ });
+ var my_aspects = [{ name: 'Work', selected: true },
+ { name: 'Friends', selected: false },
+ { name: 'Acquaintances', selected: false }]
+ this.aspects = new app.collections.Aspects(my_aspects);
+ });
+
+ describe("#selectAll", function(){
+ it("selects every aspect in the collection", function(){
+ this.aspects.selectAll();
+ this.aspects.each(function(aspect){
+ expect(aspect.get('selected')).toBeTruthy();
+ });
+ });
+ });
+
+ describe("#deselectAll", function(){
+ it("deselects every aspect in the collection", function(){
+ this.aspects.deselectAll();
+ this.aspects.each(function(aspect){
+ expect(aspect.get('selected')).toBeFalsy();
+ });
+ });
+ });
+
+ describe("#allSelected", function(){
+ it("returns true if every aspect is selected", function(){
+ this.aspects.at(1).set('selected', true);
+ this.aspects.at(2).set('selected', true);
+ expect(this.aspects.allSelected()).toBeTruthy();
+ });
+
+ it("returns false if at least one aspect is not selected", function(){
+ expect(this.aspects.allSelected()).toBeFalsy();
+ });
+ });
+
+ describe("#toSentence", function(){
+ describe('without aspects', function(){
+ beforeEach(function(){
+ this.aspects = new app.collections.Aspects({ name: 'Work', selected: false })
+ spyOn(this.aspects, 'selectedAspects').andCallThrough();
+ });
+
+ it("returns the name of the aspect", function(){
+ expect(this.aspects.toSentence()).toEqual('My Aspects');
+ expect(this.aspects.selectedAspects).toHaveBeenCalled();
+ });
+ });
+
+ describe("with one aspect", function(){
+ beforeEach(function(){
+ this.aspects = new app.collections.Aspects({ name: 'Work', selected: true })
+ spyOn(this.aspects, 'selectedAspects').andCallThrough();
+ });
+
+ it("returns the name of the aspect", function(){
+ expect(this.aspects.toSentence()).toEqual('Work');
+ expect(this.aspects.selectedAspects).toHaveBeenCalled();
+ });
+ });
+
+ describe("with three aspect", function(){
+ it("returns the name of the selected aspect", function(){
+ expect(this.aspects.toSentence()).toEqual('Work');
+ });
+
+ it("returns the names of the two selected aspects", function(){
+ this.aspects.at(1).set('selected', true);
+ expect(this.aspects.toSentence()).toEqual('Work and Friends');
+ });
+
+ it("returns the names of the selected aspects in a comma-separated sentence", function(){
+ this.aspects.at(1).set('selected', true);
+ this.aspects.at(2).set('selected', true);
+ expect(this.aspects.toSentence()).toEqual('Work, Friends and Acquaintances');
+ });
+ });
+ });
+
+ describe("#selectedAspects", function(){
+ describe("by name", function(){
+ it("returns the names of the selected aspects", function(){
+ expect(this.aspects.selectedAspects('name')).toEqual(["Work"]);
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/app/models/aspect_spec.js b/spec/javascripts/app/models/aspect_spec.js
new file mode 100644
index 000000000..72ab56047
--- /dev/null
+++ b/spec/javascripts/app/models/aspect_spec.js
@@ -0,0 +1,15 @@
+describe("app.models.Aspect", function(){
+ describe("#toggleSelected", function(){
+ it("should select the aspect", function(){
+ this.aspect = new app.models.Aspect({ name: 'John Doe', selected: false });
+ this.aspect.toggleSelected();
+ expect(this.aspect.get("selected")).toBeTruthy();
+ });
+
+ it("should deselect the aspect", function(){
+ this.aspect = new app.models.Aspect({ name: 'John Doe', selected: true });
+ this.aspect.toggleSelected();
+ expect(this.aspect.get("selected")).toBeFalsy();
+ });
+ });
+});
diff --git a/spec/javascripts/app/views/aspect_view_spec.js b/spec/javascripts/app/views/aspect_view_spec.js
new file mode 100644
index 000000000..cfdbb387d
--- /dev/null
+++ b/spec/javascripts/app/views/aspect_view_spec.js
@@ -0,0 +1,42 @@
+describe("app.views.Aspect", function(){
+ beforeEach(function(){
+ this.aspect = new app.models.Aspect({ name: 'Acquaintances', selected: true });
+ this.view = new app.views.Aspect({ model: this.aspect });
+ });
+
+ describe("render", function(){
+ beforeEach(function(){
+ this.view.render();
+ });
+
+ it('should show the aspect selected', function(){
+ expect(this.view.$el.hasClass('active')).toBeTruthy();
+ });
+
+ it('should show the name of the aspect', function(){
+ expect(this.view.$('a.aspect_selector').text()).toMatch('Acquaintances');
+ });
+
+ describe('selecting aspects', function(){
+ beforeEach(function(){
+ app.router = new app.Router();
+ spyOn(app.router, 'aspects_stream');
+ spyOn(this.view, 'toggleAspect').andCallThrough();
+ this.view.delegateEvents();
+ });
+
+ it('it should deselect the aspect', function(){
+ this.view.$('a.aspect_selector').trigger('click');
+ expect(this.view.toggleAspect).toHaveBeenCalled();
+ expect(this.view.$el.hasClass('active')).toBeFalsy();
+ expect(app.router.aspects_stream).toHaveBeenCalled();
+ });
+
+ it('should call #toggleSelected on the model', function(){
+ spyOn(this.aspect, 'toggleSelected');
+ this.view.$('a.aspect_selector').trigger('click');
+ expect(this.aspect.toggleSelected).toHaveBeenCalled();
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/app/views/aspects_list_view_spec.js b/spec/javascripts/app/views/aspects_list_view_spec.js
new file mode 100644
index 000000000..27b5ed972
--- /dev/null
+++ b/spec/javascripts/app/views/aspects_list_view_spec.js
@@ -0,0 +1,61 @@
+describe("app.views.AspectsList", function(){
+ beforeEach(function(){
+ setFixtures('');
+ Diaspora.I18n.loadLocale({ aspect_navigation : {
+ 'select_all' : 'Select all',
+ 'deselect_all' : 'Deselect all'
+ }});
+
+ var aspects = [{ name: 'Work', selected: true },
+ { name: 'Friends', selected: false },
+ { name: 'Acquaintances', selected: false }];
+ this.aspects = new app.collections.Aspects(aspects);
+ this.view = new app.views.AspectsList({ collection: this.aspects });
+ });
+
+ describe('rendering', function(){
+ beforeEach(function(){
+ this.view.render();
+ });
+
+ it('should show the corresponding aspects selected', function(){
+ expect(this.view.$('.active').length).toBe(1);
+ expect(this.view.$('.active > .aspect_selector').text()).toMatch('Work');
+ });
+
+ it('should show all the aspects', function(){
+ var aspect_selectors = this.view.$('.aspect_selector');
+ expect(aspect_selectors.length).toBe(3)
+ expect(aspect_selectors[0].text).toMatch('Work');
+ expect(aspect_selectors[1].text).toMatch('Friends');
+ expect(aspect_selectors[2].text).toMatch('Acquaintances');
+ });
+
+ it('should show \'Select all\' link', function(){
+ expect(this.view.$('.toggle_selector').text()).toMatch('Select all');
+ });
+
+ describe('selecting aspects', function(){
+ context('selecting all aspects', function(){
+ beforeEach(function(){
+ app.router = new app.Router();
+ spyOn(app.router, 'aspects_stream');
+ spyOn(this.view, 'toggleAll').andCallThrough();
+ spyOn(this.view, 'toggleSelector').andCallThrough();
+ this.view.delegateEvents();
+ this.view.$('.toggle_selector').click();
+ });
+
+ it('should show all the aspects selected', function(){
+ expect(this.view.toggleAll).toHaveBeenCalled();
+ expect(this.view.$('li.active').length).toBe(3);
+ });
+
+ it('should show \'Deselect all\' link', function(){
+ expect(this.view.toggleSelector).toHaveBeenCalled();
+ expect(this.view.$('.toggle_selector').text()).toMatch('Deselect all');
+ });
+ });
+ });
+ });
+});
diff --git a/spec/presenters/user_presenter_spec.rb b/spec/presenters/user_presenter_spec.rb
index 2f322b497..38720dcb3 100644
--- a/spec/presenters/user_presenter_spec.rb
+++ b/spec/presenters/user_presenter_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe UserPresenter do
before do
- @presenter = UserPresenter.new(bob)
+ @presenter = UserPresenter.new(bob, [])
end
describe '#to_json' do
@@ -34,4 +34,4 @@ describe UserPresenter do
@presenter.configured_services.should include("fakebook")
end
end
-end
\ No newline at end of file
+end