From 976ff0fcdadeef676837db19ce6fe6d79fa825be Mon Sep 17 00:00:00 2001 From: Steffen van Bergerem <svbergerem@online.de> Date: Fri, 19 Sep 2014 20:08:36 +0200 Subject: [PATCH] Redesign profile page and port to Bootstrap --- Changelog.md | 1 + ...-s729fe6854c.png => icons-s71323e8d98.png} | Bin 50791 -> 50590 bytes app/assets/images/icons/circle.png | Bin 255 -> 0 bytes .../app/helpers/handlebars-helpers.js | 27 ++- app/assets/javascripts/app/pages/profile.js | 10 +- app/assets/javascripts/app/router.js | 5 +- .../app/views/conversations_form_view.js | 27 +++ .../app/views/conversations_view.js | 17 +- .../app/views/profile_header_view.js | 32 ++- .../app/views/profile_sidebar_view.js | 35 +-- app/assets/javascripts/inbox.js | 1 - app/assets/stylesheets/application.css.sass | 1 - app/assets/stylesheets/comments.css.scss | 1 + app/assets/stylesheets/contacts.css.scss | 3 +- app/assets/stylesheets/conversations.css.scss | 29 +-- app/assets/stylesheets/new-templates.css.scss | 1 + .../stylesheets/new_styles/_interactions.scss | 2 +- app/assets/stylesheets/new_styles/_navs.scss | 5 +- app/assets/stylesheets/profile.css.scss | 221 +++++++++--------- .../stylesheets/single-post-view.css.scss | 2 +- .../stylesheets/stream_element.css.scss | 3 +- app/assets/stylesheets/tag.css.scss | 2 + .../templates/profile_header_tpl.jst.hbs | 119 +++++++--- .../templates/profile_sidebar_tpl.jst.hbs | 67 +----- app/controllers/conversations_controller.rb | 2 +- app/controllers/people_controller.rb | 42 ++-- app/controllers/photos_controller.rb | 25 +- app/helpers/aspect_global_helper.rb | 17 +- app/helpers/contacts_helper.rb | 6 +- app/helpers/people_helper.rb | 26 --- app/models/contact.rb | 11 + .../_aspect_membership_dropdown.html.haml | 2 +- app/views/contacts/_header.html.haml | 7 +- app/views/contacts/index.html.haml | 7 + app/views/conversations/new.html.haml | 11 + .../{new.haml => new.mobile.haml} | 5 +- app/views/notifications/index.html.haml | 5 +- .../people/_aspect_membership_dropdown.haml | 2 +- app/views/people/_profile_sidebar.html.haml | 90 ------- app/views/people/_sub_header.html.haml | 34 --- app/views/people/contacts.haml | 48 ++-- app/views/people/show.html.haml | 48 ++-- app/views/status_messages/new.html.haml | 22 +- config/locales/javascript/javascript.en.yml | 1 + features/desktop/connects_users.feature | 14 +- features/desktop/contacts.feature | 11 +- .../mentions_from_profile_page.feature | 12 +- features/desktop/profile_photos.feature | 22 +- features/step_definitions/aspects_steps.rb | 10 +- features/step_definitions/custom_web_steps.rb | 8 +- features/step_definitions/posts_steps.rb | 2 +- features/support/paths.rb | 4 +- .../conversations_controller_spec.rb | 14 +- spec/helpers/people_helper_spec.rb | 22 -- .../app/views/profile_header_view_spec.js | 7 + .../app/views/profile_sidebar_view_spec.js | 7 +- .../app/views/publisher_view_spec.js | 12 +- 57 files changed, 537 insertions(+), 630 deletions(-) rename app/assets/images/{icons-s729fe6854c.png => icons-s71323e8d98.png} (56%) delete mode 100644 app/assets/images/icons/circle.png create mode 100644 app/assets/javascripts/app/views/conversations_form_view.js create mode 100644 app/views/conversations/new.html.haml rename app/views/conversations/{new.haml => new.mobile.haml} (93%) delete mode 100644 app/views/people/_profile_sidebar.html.haml delete mode 100644 app/views/people/_sub_header.html.haml diff --git a/Changelog.md b/Changelog.md index 9a2b9a8bc0..c5311e21c0 100644 --- a/Changelog.md +++ b/Changelog.md @@ -42,6 +42,7 @@ The default for including jQuery from a CDN has changed. If you want to continue * Display new conversation form on conversations/index [#5178](https://github.com/diaspora/diaspora/pull/5178) * Port profile page to Backbone [#5180](https://github.com/diaspora/diaspora/pull/5180) * Pull punycode.js from rails-assets.org [#5263](https://github.com/diaspora/diaspora/pull/5263) +* Redesign profile page and port to Bootstrap [#4657](https://github.com/diaspora/diaspora/pull/4657) ## Bug fixes diff --git a/app/assets/images/icons-s729fe6854c.png b/app/assets/images/icons-s71323e8d98.png similarity index 56% rename from app/assets/images/icons-s729fe6854c.png rename to app/assets/images/icons-s71323e8d98.png index 5e134f8093273d5cc08e084b74508eff123bc303..026503b9a05591e4716e27fcc3e4fbb7f385f46e 100644 GIT binary patch delta 21538 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 delta 21608 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 diff --git a/app/assets/images/icons/circle.png b/app/assets/images/icons/circle.png deleted file mode 100644 index 944a88391157bcdaabb044d44273b77ae6505554..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 255 zcmeAS@N?(olHy`uVBq!ia0y~yU=RXf4mJh`hOl#e;S3B6Y)RhkE(~Ds(|LD20|NtR zfk$L90|U1(2s1Lwnj^u$z`$PO>FdgVmxD`0UEtx9<&g{w43Z_T5hc#~xw)x%B@E6* zsfi`2DGKG8B^e6tp1uL$jeOz^3=HX>E{-7<r{7LG$a_G6!!_Qjk-1dAJW=pj65}my zU(d_U%f3AG?s)dULF3RPZtDdNt{EA@B@Y;EuI+hmJU6D3&!c5|lJne5uPo1e&+8MN y#Fn4xR)2W&@{NCU!fswYCAT~0&r<oK!eXYo>L!Q(i{@SfdBoGz&t;ucLK6V>H&vtn diff --git a/app/assets/javascripts/app/helpers/handlebars-helpers.js b/app/assets/javascripts/app/helpers/handlebars-helpers.js index 1be1cd98d0..cea31311af 100644 --- a/app/assets/javascripts/app/helpers/handlebars-helpers.js +++ b/app/assets/javascripts/app/helpers/handlebars-helpers.js @@ -31,18 +31,18 @@ Handlebars.registerHelper('linkToPerson', function(context, block) { }); // relationship indicator for profile page -Handlebars.registerHelper('sharingBadge', function(person) { +Handlebars.registerHelper('sharingMessage', function(person) { var i18n_scope = 'people.helper.is_not_sharing'; - var icon = 'icons-circle'; + var icon = "circle"; if( person.is_sharing ) { i18n_scope = 'people.helper.is_sharing'; - icon = 'icons-check_yes_ok'; + icon = "entypo check"; } var title = Diaspora.I18n.t(i18n_scope, {name: person.name}); - var html = '<div class="sharing_message_container" title="'+title+'" data-placement="bottom">'+ - ' <div id="sharing_message" class="'+icon+'"></div>'+ - '</div>'; + var html = '<span class="sharing_message_container" title="'+title+'" data-placement="bottom">'+ + ' <i id="sharing_message" class="'+icon+'"></i>'+ + '</span>'; return html; }); @@ -90,3 +90,18 @@ Handlebars.registerHelper('fmtTags', function(tags) { Handlebars.registerHelper('fmtText', function(text) { return new Handlebars.SafeString(app.helpers.textFormatter(text, null)); }); + +Handlebars.registerHelper('isCurrentPage', function(path_helper, id, options){ + var currentPage = "/"+Backbone.history.fragment; + if (currentPage == Handlebars.helpers.urlTo(path_helper, id, options.data)) { + return options.fn(this); + } else { + return options.inverse(this); + } +}); + +Handlebars.registerHelper('isCurrentProfilePage', function(id, diaspora_handle, options){ + var username = diaspora_handle.split("@")[0]; + return Handlebars.helpers.isCurrentPage('person', id, options) || + Handlebars.helpers.isCurrentPage('user_profile', username, options); +}); diff --git a/app/assets/javascripts/app/pages/profile.js b/app/assets/javascripts/app/pages/profile.js index 3aa9fb1015..32298e364b 100644 --- a/app/assets/javascripts/app/pages/profile.js +++ b/app/assets/javascripts/app/pages/profile.js @@ -11,7 +11,7 @@ app.pages.Profile = app.views.Base.extend({ '#main_stream': 'streamView' }, - tooltipSelector: '.profile_button div, .sharing_message_container', + tooltipSelector: '.profile_button .profile-header-icon, .sharing_message_container', initialize: function(opts) { if( !this.model ) { @@ -52,14 +52,16 @@ app.pages.Profile = app.views.Base.extend({ if( !this.model.has('profile') ) return false; return new app.views.ProfileSidebar({ model: this.model, - photos: this.photos, - contacts: this.contacts }); }, headerView: function() { if( !this.model.has('profile') ) return false; - return new app.views.ProfileHeader({model: this.model}); + return new app.views.ProfileHeader({ + model: this.model, + photos: this.photos, + contacts: this.contacts + }); }, streamView: function() { diff --git a/app/assets/javascripts/app/router.js b/app/assets/javascripts/app/router.js index 55943e94e0..df6e4ff739 100644 --- a/app/assets/javascripts/app/router.js +++ b/app/assets/javascripts/app/router.js @@ -21,6 +21,7 @@ app.Router = Backbone.Router.extend({ "followed_tags": "followed_tags", "tags/:name": "followed_tags", "people/:id/photos": "photos", + "people/:id/contacts": "profile", "people/:id": "profile", "u/:name": "profile" @@ -81,7 +82,7 @@ app.Router = Backbone.Router.extend({ this.renderPage(function() { return new app.pages.Profile({ person_id: guid, - el: $('body > .container'), + el: $('body > .container-fluid'), streamCollection: app.collections.Photos, streamView: app.views.Photos }); @@ -147,7 +148,7 @@ app.Router = Backbone.Router.extend({ profile: function() { this.renderPage(function() { return new app.pages.Profile({ - el: $('body > .container') + el: $('body > .container-fluid') }); }); } }); diff --git a/app/assets/javascripts/app/views/conversations_form_view.js b/app/assets/javascripts/app/views/conversations_form_view.js new file mode 100644 index 0000000000..4134a303ed --- /dev/null +++ b/app/assets/javascripts/app/views/conversations_form_view.js @@ -0,0 +1,27 @@ +app.views.ConversationsForm = Backbone.View.extend({ + + initialize: function(opts) { + this.contacts = _.has(opts, 'contacts') ? opts.contacts : null; + this.prefill = []; + if (_.has(opts, 'prefillName') && _.has(opts, 'prefillValue')) { + this.prefill = [{name : opts.prefillName, + value : opts.prefillValue}]; + } + this.autocompleteInput = $("#contact_autocomplete"); + this.prepareAutocomplete(this.contacts); + }, + + prepareAutocomplete: function(data){ + this.autocompleteInput.autoSuggest(data, { + selectedItemProp: "name", + searchObjProps: "name", + asHtmlID: "contact_ids", + retrieveLimit: 10, + minChars: 1, + keyDelay: 0, + startText: '', + emptyText: Diaspora.I18n.t('no_results'), + preFill: this.prefill + }).focus(); + } +}); diff --git a/app/assets/javascripts/app/views/conversations_view.js b/app/assets/javascripts/app/views/conversations_view.js index c2701efa4b..b697d37c19 100644 --- a/app/assets/javascripts/app/views/conversations_view.js +++ b/app/assets/javascripts/app/views/conversations_view.js @@ -13,8 +13,8 @@ app.views.Conversations = Backbone.View.extend({ if ($('#first_unread').length > 0) { $("html").scrollTop($('#first_unread').offset().top-50); } - this.autocompleteInput = $("#contact_autocomplete"); - this.prepareAutocomplete(gon.contacts); + + new app.views.ConversationsForm({contacts: gon.contacts}); $('.timeago').each(function(i,e) { var jqe = $(e); @@ -30,18 +30,5 @@ app.views.Conversations = Backbone.View.extend({ showParticipants: function(e){ $(e.currentTarget).find('.participants').slideDown('300'); - }, - - prepareAutocomplete: function(data){ - this.autocompleteInput.autoSuggest(data, { - selectedItemProp: "name", - searchObjProps: "name", - asHtmlID: "contact_ids", - retrieveLimit: 10, - minChars: 1, - keyDelay: 0, - startText: '', - emptyText: Diaspora.I18n.t('no_results'), - }).focus(); } }); diff --git a/app/assets/javascripts/app/views/profile_header_view.js b/app/assets/javascripts/app/views/profile_header_view.js index 971cfacce8..656c3dabdc 100644 --- a/app/assets/javascripts/app/views/profile_header_view.js +++ b/app/assets/javascripts/app/views/profile_header_view.js @@ -2,14 +2,24 @@ app.views.ProfileHeader = app.views.Base.extend({ templateName: 'profile_header', - initialize: function() { + initialize: function(opts) { app.events.on('aspect:create', this.postRenderTemplate, this); + this.photos = _.has(opts, 'photos') ? opts.photos : null; + this.contacts = _.has(opts, 'contacts') ? opts.contacts : null; }, presenter: function() { return _.extend({}, this.defaultPresenter(), { + show_profile_btns: this._shouldShowProfileBtns(), + show_photos: this._shouldShowPhotos(), + show_contacts: this._shouldShowContacts(), is_blocked: this.model.isBlocked(), - has_tags: this._hasTags() + is_sharing: this.model.isSharing(), + is_receiving: this.model.isReceiving(), + is_mutual: this.model.isMutual(), + has_tags: this._hasTags(), + contacts: this.contacts, + photos: this.photos }); }, @@ -17,6 +27,18 @@ app.views.ProfileHeader = app.views.Base.extend({ return (this.model.get('profile')['tags'].length > 0); }, + _shouldShowProfileBtns: function() { + return (app.currentUser.authenticated() && !this.model.get('is_own_profile')); + }, + + _shouldShowPhotos: function() { + return (this.photos && this.photos.count > 0); + }, + + _shouldShowContacts: function() { + return (this.contacts && this.contacts.count > 0); + }, + postRenderTemplate: function() { var self = this; var dropdownEl = this.$('.aspect_membership_dropdown.placeholder'); @@ -26,16 +48,16 @@ app.views.ProfileHeader = app.views.Base.extend({ } // TODO render me client side!!! - var href = this.model.url() + '/aspect_membership_button?create=true'; + var href = this.model.url() + '/aspect_membership_button?create=true&size=normal'; if( gon.bootstrap ) href += '&bootstrap=true'; $.get(href, function(resp) { dropdownEl.html(resp); - new app.views.AspectMembership({el: dropdownEl}); + new app.views.AspectMembership({el: $('.aspect_dropdown',dropdownEl)}); // UGLY (re-)attach the facebox self.$('a[rel*=facebox]').facebox(); - this._done(); + self._done(); }); }, diff --git a/app/assets/javascripts/app/views/profile_sidebar_view.js b/app/assets/javascripts/app/views/profile_sidebar_view.js index f45f18f33b..d94871cf33 100644 --- a/app/assets/javascripts/app/views/profile_sidebar_view.js +++ b/app/assets/javascripts/app/views/profile_sidebar_view.js @@ -2,44 +2,13 @@ app.views.ProfileSidebar = app.views.Base.extend({ templateName: 'profile_sidebar', - initialize: function(opts) { - this.photos = _.has(opts, 'photos') ? opts.photos : null; - this.contacts = _.has(opts, 'contacts') ? opts.contacts : null; - }, - presenter: function() { return _.extend({}, this.defaultPresenter(), { - do_profile_btns: this._shouldDoProfileBtns(), - do_profile_info: this._shouldDoProfileInfo(), - do_photos: this._shouldDoPhotos(), - do_contacts: this._shouldDoContacts(), - is_sharing: this.model.isSharing(), - is_receiving: this.model.isReceiving(), - is_mutual: this.model.isMutual(), - is_not_blocked: !this.model.isBlocked(), - photos: this.photos, - contacts: this.contacts + show_profile_info: this._shouldShowProfileInfo(), }); }, - _shouldDoProfileBtns: function() { - return (app.currentUser.authenticated() && !this.model.get('is_own_profile')); - }, - - _shouldDoProfileInfo: function() { + _shouldShowProfileInfo: function() { return (this.model.isSharing() || this.model.get('is_own_profile')); - }, - - _shouldDoPhotos: function() { - return (this.photos && this.photos.items.length > 0); - }, - - _shouldDoContacts: function() { - return (this.contacts && this.contacts.items.length > 0); - }, - - postRenderTemplate: function() { - // UGLY (re-)attach the facebox - this.$('a[rel*=facebox]').facebox(); } }); diff --git a/app/assets/javascripts/inbox.js b/app/assets/javascripts/inbox.js index c7892eb34b..4b7488bd0c 100644 --- a/app/assets/javascripts/inbox.js +++ b/app/assets/javascripts/inbox.js @@ -2,7 +2,6 @@ * licensed under the Affero General Public License version 3 or later. See * the COPYRIGHT file. */ -//= require jquery.autoSuggest.custom $(document).ready(function(){ $(document).on('click', '.conversation-wrapper', function(){ diff --git a/app/assets/stylesheets/application.css.sass b/app/assets/stylesheets/application.css.sass index 376babb344..5e52dbd1a0 100644 --- a/app/assets/stylesheets/application.css.sass +++ b/app/assets/stylesheets/application.css.sass @@ -13,7 +13,6 @@ @import 'opengraph' @import 'poll' @import 'help' -@import 'profile' @import 'publisher_blueprint' @import 'facebox' @import 'aspects' diff --git a/app/assets/stylesheets/comments.css.scss b/app/assets/stylesheets/comments.css.scss index 681bca0661..5d4e453613 100644 --- a/app/assets/stylesheets/comments.css.scss +++ b/app/assets/stylesheets/comments.css.scss @@ -38,4 +38,5 @@ width: 95%; } .comment_box { width: 95%; } + .comment_box:focus { min-height: 100px; } } diff --git a/app/assets/stylesheets/contacts.css.scss b/app/assets/stylesheets/contacts.css.scss index fe872dd27b..56ad441d30 100644 --- a/app/assets/stylesheets/contacts.css.scss +++ b/app/assets/stylesheets/contacts.css.scss @@ -19,7 +19,8 @@ width: 150px; &:focus { width: 250px; } } - & > a, #aspect_controls > a { + #aspect_controls > .contacts_button { + cursor: pointer; text-decoration: none; margin-right: 25px; } diff --git a/app/assets/stylesheets/conversations.css.scss b/app/assets/stylesheets/conversations.css.scss index 313c72eabd..72fe60ce9e 100644 --- a/app/assets/stylesheets/conversations.css.scss +++ b/app/assets/stylesheets/conversations.css.scss @@ -210,32 +210,5 @@ #new_conversation_pane { ul.as-selections { width: 100% !important; } input#contact_ids { box-shadow: none; } - textarea { width: 98%; } - - .bottom_submit_section { - text-align: right; - } - - .button.creation { - $button-border-color: #aaa; - @include border-radius(3px); - @include box-shadow(0,1px,1px,#cfcfcf); - @include transition(border); - @include button-gradient($creation-blue); - font-size: 12px; - color: #fff; - padding: 4px 9px; - min-width: 90px; - min-height: 10px; - border: 1px solid darken($button-border-color,20%); - - cursor: pointer; - white-space: nowrap; - - &:hover { - @include button-gradient-hover($creation-blue); - border: 1px solid darken($button-border-color,35%); - text-decoration: none; - } - } + label { font-weight: bold; } } diff --git a/app/assets/stylesheets/new-templates.css.scss b/app/assets/stylesheets/new-templates.css.scss index 98b38fdc35..63ccacb285 100644 --- a/app/assets/stylesheets/new-templates.css.scss +++ b/app/assets/stylesheets/new-templates.css.scss @@ -59,6 +59,7 @@ /* people */ @import 'people'; @import 'invitations'; +@import 'profile'; /* stream */ @import 'tag'; diff --git a/app/assets/stylesheets/new_styles/_interactions.scss b/app/assets/stylesheets/new_styles/_interactions.scss index 63858cb6bf..1f3c57c421 100644 --- a/app/assets/stylesheets/new_styles/_interactions.scss +++ b/app/assets/stylesheets/new_styles/_interactions.scss @@ -21,7 +21,7 @@ } } - .stream_element, .comment, .stream_element:hover .comment { + .stream_element, .comment, .photo, .stream_element:hover .comment { .controls > a { @include opacity(0); } &:hover .controls { diff --git a/app/assets/stylesheets/new_styles/_navs.scss b/app/assets/stylesheets/new_styles/_navs.scss index f433eebf15..d93871c929 100644 --- a/app/assets/stylesheets/new_styles/_navs.scss +++ b/app/assets/stylesheets/new_styles/_navs.scss @@ -1,14 +1,15 @@ .nav.nav-tabs{ li > a { color: $text-dark-grey; - .entypo { + .entypo, .mentionIcon { color: $text-dark-grey; margin-right: 5px; } + .mentionIcon { font-weight: 700; } } li.active > a { background-color: $background-grey; color: $black; - .entypo { color: $black; } + .entypo, .mentionIcon { color: $black; } } } diff --git a/app/assets/stylesheets/profile.css.scss b/app/assets/stylesheets/profile.css.scss index bf2338591c..aabcb0e2eb 100644 --- a/app/assets/stylesheets/profile.css.scss +++ b/app/assets/stylesheets/profile.css.scss @@ -1,127 +1,122 @@ +#profile_container { + .profile_header { + border-bottom: 1px solid $border-grey; + margin-bottom: 20px; -.profile_photo { - img { - height: auto; - width: 200px; - } -} - -#profile { - h3 { margin-bottom: 0; } - ul { - margin: 0; - padding: 0; - } - - .avatar.large { margin-bottom: 0; } - - ul#profile_information { - margin: 1em 0; - > li { - margin-bottom: 2em; - margin-right: 2em; - h4 { font-weight: bold; } - } - } - - .image_list { - .section { - margin-bottom: 4px; + #edit_profile, #unblock_user_button, .aspect_dropdown { + margin-top: 5px; + margin-right: 10px; } - img { - height: 45px; - width: 45px; - } - } - .blocked { - background-color: rgb(244, 42, 42); - .profile_button { - width: 150px; - } - } - .mutual { - background-color: rgb(142, 222, 61); - .profile_button { - width: 50px; - } - } - .sharing { - background-color: rgb(142, 222, 61); - .profile_button { - width: 150px; - } - } - .receiving { - background-color: rgb(211, 211, 211); - .profile_button { - width: 75px; - } - } - .not_sharing { - background-color: rgb(211, 211, 211); - .profile_button { - width: 150px; + #author_info { + h2 { + line-height: 35px; + margin-top: 10px; + margin-bottom: 0px; + } + #name { + font-weight: 700; + } + #diaspora_handle { + color: $text-grey; + font-size: 20px; + } + #sharing_message { + cursor: default; + font-size: 20px; + &.circle { + color: $light-grey; + &:before { content: '\26aa'; } + } + &.entypo.check { color: darken($green,20%); } + } + .description { + margin-bottom: 20px; + .tag { + background-color: transparent; + font-size: 14px; + } + .tag:not(.entypo) { + font-weight: 700; + } + .entypo.tag { + margin: 0 5px; + font-weight: normal; + &:hover {text-decoration: none;} + } + } } - } - #profile_buttons { - width: 190px; - padding-right: 10px; - height: 28px; - text-align: center; - @include border-bottom-radius(8px); + #profile_horizontal_bar { + border-top: 1px dashed $border-grey; + min-height: 50px; + margin-top: 10px; + #profile_buttons { + padding: 10px 0; + > .profile_button { + text-decoration: none; + cursor: pointer; + margin-right: 25px; + .entypo.profile-header-icon, .profile-header-icon { + font-size: 24.5px; + line-height: 30px; + color: lighten($black,75%); + &:hover { color: $black; } + } + #mention_button { font-weight: 700; } + } + } - .sharing_message_container { - float: left; - padding: 5px 1px; - @include opacity(0.3); - background-color: white; - @include border-bottom-left-radius(8px); + ul#profile_nav { + list-style: none; + margin: 0; + > li { + display: inline-block; + &.active { + border-bottom: 3px solid $creation-blue; + a { + color: $black; + .entypo { color: $black; } + } + } + a { + padding: 10px 15px; + font-size: 16px; + line-height: 46px; + color: lighten($black,50%); + .entypo { + color: lighten($black,50%); + margin-right: 2px; + } + &:hover { + color: $black; + .entypo { color: $black; } + text-decoration: none; + } + } + } + } } + } - .profile_button { - display: inline-block; + #profile { + border-right: 1px solid $border-grey; + padding: 10px 20px; + #profile_photo { + margin-top: 10px; + padding-bottom: 10px; + border-bottom: 1px dashed $border-grey; text-align: center; } - a { @include opacity(0.5); } - a:hover { @include opacity(1); } - - .icons-check_yes_ok { - display: inline-block; - height: 18px; - width: 18px; - } - .icons-circle { - display: inline-block; - height: 18px; - width: 18px; - } - .icons-ignoreuser { - display: inline-block; - height: 14px; - width: 14px; - margin: 7px 0; - } - .icons-mention { - display: inline-block; - height: 18px; - width: 19px; - margin: 5px 0; - } - .icons-message { - display: inline-block; - height: 18px; - width: 25px; - margin: 5px 0; - } - .white_bar { - display: inline-block; - height: 18px; - width: 1px; - background-color: white; - margin: 5px 0; + ul#profile_information { + margin: 0; + list-style: none; + > li { + margin-bottom: 2em; + h4 { font-weight: bold; } + } } + } } diff --git a/app/assets/stylesheets/single-post-view.css.scss b/app/assets/stylesheets/single-post-view.css.scss index 2fbb510017..bcf1043203 100644 --- a/app/assets/stylesheets/single-post-view.css.scss +++ b/app/assets/stylesheets/single-post-view.css.scss @@ -165,7 +165,7 @@ border-bottom: none; } a { - color: #3f8fba; + color: $blue; } .count { i { diff --git a/app/assets/stylesheets/stream_element.css.scss b/app/assets/stylesheets/stream_element.css.scss index f40c606bfb..16c29e7363 100644 --- a/app/assets/stylesheets/stream_element.css.scss +++ b/app/assets/stylesheets/stream_element.css.scss @@ -1,4 +1,4 @@ -#main_stream .stream_element { +#main_stream .stream_element, #main_stream .photo { padding: 10px; border-bottom: 1px solid $border-grey; @@ -13,6 +13,7 @@ margin-bottom: 4px; unicode-bidi: bidi-override; } + a.author { color: $blue; } .feedback { margin-top: 5px; font-size: 11px; diff --git a/app/assets/stylesheets/tag.css.scss b/app/assets/stylesheets/tag.css.scss index 1ee8427bb7..5e99f92476 100644 --- a/app/assets/stylesheets/tag.css.scss +++ b/app/assets/stylesheets/tag.css.scss @@ -7,6 +7,8 @@ } } +a.tag { color: $blue; } + h1.tag { border-bottom: 2px dotted $blue; &:hover { border-bottom: 2px dotted $blue; } diff --git a/app/assets/templates/profile_header_tpl.jst.hbs b/app/assets/templates/profile_header_tpl.jst.hbs index 9b2832d27c..516ae8345f 100644 --- a/app/assets/templates/profile_header_tpl.jst.hbs +++ b/app/assets/templates/profile_header_tpl.jst.hbs @@ -1,39 +1,104 @@ -<div id="author_info"> - {{#if loggedIn}} - <div class="right"> - {{#if is_own_profile}} - {{!-- can't block myself, so don't check it here --}} - <a href="{{urlTo 'edit_profile'}}" class="button creation">{{t 'people.edit_my_profile'}}</a> - {{else}} {{#if is_blocked}} - <a href="#" id="unblock_user_button" class="button">{{t 'people.stop_ignoring'}}</a> - {{else}} - <div class="placeholder aspect_membership_dropdown"></div> - {{/if}}{{/if}} - </div> - {{/if}} +{{#if loggedIn}} + <div class="pull-right"> + {{#if is_own_profile}} + {{!-- can't block myself, so don't check it here --}} + <a href="{{urlTo 'edit_profile'}}" id="edit_profile" class="btn btn-primary creation">{{t 'people.edit_my_profile'}}</a> + {{else}} {{#if is_blocked}} + <a href="#" id="unblock_user_button" class="btn btn-danger">{{t 'people.stop_ignoring'}}</a> + {{else}} + <div class="placeholder aspect_membership_dropdown"></div> + {{/if}}{{/if}} + </div> +{{/if}} - <h2>{{name}}</h2> - <span class="diaspora_handle">{{diaspora_id}}</span> +<div id="author_info"> + <h2> + <span id="name">{{name}}</span> + <span id="diaspora_handle">{{diaspora_id}}</span> + {{#if show_profile_btns}} + {{{sharingMessage this}}} + {{/if}} + </h2> {{#if loggedIn}} - <div class="description"> - {{#if has_tags}} + {{#if has_tags}} + <div class="description"> + <i class="entypo tag"></i> {{fmtTags profile.tags}} - {{#if is_own_profile}} - <span class="hover_edit"> - <a href="{{urlTo 'edit_profile'}}">{{t 'profile.edit'}}</a> - </span> - {{/if}} - {{else}} - {{#if is_own_profile}} + </div> + {{else}} + {{#if is_own_profile}} + <div class="description"> <i>{{t 'profile.you_have_no_tags'}}</i> <span class="add_tags"> <a href="{{urlTo 'edit_profile'}}">{{t 'profile.add_some'}}</a> </span> - {{/if}} + </div> {{/if}} - </div> + {{/if}} {{/if}} </div> -<hr /> +{{#if loggedIn}} + <div id="profile_horizontal_bar"> + {{#if show_profile_btns}} + <div id="profile_buttons" class="pull-right"> + {{#if is_receiving}} + {{!-- create status message with mention --}} + <span class="profile_button"> + <span id="mention_button" class="profile-header-icon" title="{{t 'people.mention'}}" data-placement="bottom" data-toggle="modal" data-target="#mentionModal">@</span> + </span> + {{/if}} + + {{#if is_mutual}} + {{!-- create private conversation with person --}} + <span class="profile_button"> + <i id="message_button" class="entypo profile-header-icon mail" title="{{t 'people.message'}}" data-placement="bottom" data-toggle="modal" data-target="#conversationModal"></i> + </span> + {{/if}} + + {{#unless is_blocked}} + {{!-- ignore the person --}} + <a href="#" class="profile_button" rel="nofollow"> + <i id="block_user_button" class="entypo profile-header-icon block block_user" title="{{t 'ignore'}}" data-placement="bottom"></i> + </a> + {{/unless}} + </div> + {{/if}} + + <ul id="profile_nav"> + <li {{#isCurrentProfilePage guid diaspora_id}} class="active" {{/isCurrentProfilePage}}> + <a href="{{urlTo 'person' guid}}" id="posts_link"> + <i class="entypo docs"></i> + {{t 'profile.posts'}} + </a> + </li> + {{#if show_photos}} + <li {{#isCurrentPage 'person_photos' guid}} class="active" {{/isCurrentPage}}> + <a href="{{urlTo 'person_photos' guid}}" id="photos_link"> + <i class="entypo picture"></i> + {{t 'profile.photos'}} + <div class="badge badge-default">{{photos.count}}</div> + </a> + </li> + {{/if}} + {{#if show_contacts}} + <li {{#isCurrentPage 'person_contacts' guid}} class="active" {{/isCurrentPage}}> + {{#if is_own_profile}} + <a href="{{urlTo 'contacts'}}" id="contacts_link"> + <i class="entypo users"></i> + {{t 'profile.contacts'}} + <div class="badge badge-default">{{contacts.count}}</div> + </a> + {{else}} + <a href="{{urlTo 'person_contacts' guid}}" id="contacts_link"> + <i class="entypo users"></i> + {{t 'profile.contacts'}} + <div class="badge badge-default">{{contacts.count}}</div> + </a> + {{/if}} + </li> + {{/if}} + </div> + </div> +{{/if}} diff --git a/app/assets/templates/profile_sidebar_tpl.jst.hbs b/app/assets/templates/profile_sidebar_tpl.jst.hbs index 5f70552e7b..69cc76d835 100644 --- a/app/assets/templates/profile_sidebar_tpl.jst.hbs +++ b/app/assets/templates/profile_sidebar_tpl.jst.hbs @@ -5,40 +5,7 @@ {{/linkToPerson}} </div> -{{#if do_profile_btns}} - <div id="profile_buttons" class="{{relationship}}"> - {{{sharingBadge this}}} - - {{#if is_receiving}} - {{!-- create status message with mention --}} - <div class="profile_button"> - <a href="{{urlTo 'new_status_message' person_id=id}}" rel="facebox"> - <div id="mention_button" class="icons-mention" title="{{t 'people.mention'}}" data-placement="bottom"></div> - </a> - </div> - {{/if}} - - {{#if is_mutual}} - {{!-- create private conversation with person --}} - <div class="profile_button"> - <a href="{{urlTo 'new_conversation' contact_id=contact.id name=name facebox=true}}" rel="facebox"> - <div id="message_button" class="icons-message" title="{{t 'people.message'}}" data-placement="bottom"></div> - </a> - </div> - {{/if}} - - {{#if is_not_blocked}} - {{!-- ignore the person --}} - <div class="profile_button"> - <a href="#" rel="nofollow"> - <div id="block_user_button" class="icons-ignoreuser block_user" title="{{t 'ignore'}}" data-placement="bottom"></div> - </a> - </div> - {{/if}} - </div> -{{/if}} - -{{#if do_profile_info}} +{{#if show_profile_info}} <ul id="profile_information"> {{#with profile}} {{#if bio}} @@ -66,37 +33,5 @@ </li> {{/if}} {{/with}} - {{#if do_photos}} - <li class="image_list"> - <h4> - {{t 'profile.photos'}} - <div class="item_count">{{photos.count}}</div> - </h4> - <div class="section photo_pictures"> - {{#each photos.items}} - <img src="{{sizes.small}}" alt="{{guid}}" /> - {{/each}} - </div> - <p class="see_all"> - <a href="{{urlTo 'person_photos' guid}}">{{t 'header.view_all'}}</a> - </p> - </li> - {{/if}} - {{#if do_contacts}} - <li class="image_list"> - <h4> - {{t 'profile.contacts'}} - <div class="item_count">{{contacts.count}}</div> - </h4> - <div class="section contact_pictures"> - {{#each contacts.items}} - {{#linkToPerson this}}{{{personImage this "small"}}}{{/linkToPerson}} - {{/each}} - </div> - <p class="see_all"> - <a href="{{urlTo 'person_contacts' guid}}">{{t 'header.view_all'}}</a> - </p> - </li> - {{/if}} </ul> {{/if}} diff --git a/app/controllers/conversations_controller.rb b/app/controllers/conversations_controller.rb index 7a175d315a..59c8c74968 100644 --- a/app/controllers/conversations_controller.rb +++ b/app/controllers/conversations_controller.rb @@ -84,7 +84,7 @@ class ConversationsController < ApplicationController end def new - if !params[:facebox] && !session[:mobile_view] && request.format.html? + if !params[:modal] && !session[:mobile_view] && request.format.html? redirect_to conversations_path return end diff --git a/app/controllers/people_controller.rb b/app/controllers/people_controller.rb index f0782d70a4..ff2783c6a9 100644 --- a/app/controllers/people_controller.rb +++ b/app/controllers/people_controller.rb @@ -6,7 +6,8 @@ class PeopleController < ApplicationController before_action :authenticate_user!, except: [:show, :stream, :last_post] before_action :find_person, only: [:show, :stream, :hovercard] - use_bootstrap_for :index + layout ->(c){ request.format == :mobile ? "application" : "with_header_with_footer" } + use_bootstrap_for :index, :show, :contacts respond_to :html, :except => [:tag_index] respond_to :json, :only => [:index, :show] @@ -77,19 +78,19 @@ class PeopleController < ApplicationController def show mark_corresponding_notifications_read if user_signed_in? - @aspect = :profile # let aspect dropdown create new aspects @person_json = PersonPresenter.new(@person, current_user).full_hash_with_profile respond_to do |format| format.all do + if user_signed_in? + @contact = current_user.contact_for(@person) + end gon.preloads[:person] = @person_json gon.preloads[:photos] = { count: photos_from(@person).count(:all), - items: PhotoPresenter.as_collection(photos_from(@person).limit(8), :base_hash) } gon.preloads[:contacts] = { - count: contact_contacts.count(:all), - items: PersonPresenter.as_collection(contact_contacts.limit(8), :full_hash_with_avatar, current_user) + count: Contact.contact_contacts_for(current_user, @person).count(:all), } respond_with @person end @@ -144,12 +145,20 @@ class PeopleController < ApplicationController def contacts @person = Person.find_by_guid(params[:person_id]) + if @person @contact = current_user.contact_for(@person) - @aspect = :profile - @contacts_of_contact = contact_contacts.paginate(:page => params[:page], :per_page => (params[:limit] || 15)) - @contacts_of_contact_count = contact_contacts.count(:all) + @contacts_of_contact = Contact.contact_contacts_for(current_user, @person) @hashes = hashes_for_people @contacts_of_contact, @aspects + gon.preloads[:person] = PersonPresenter.new(@person, current_user).full_hash_with_profile + gon.preloads[:photos] = { + count: photos_from(@person).count(:all), + } + gon.preloads[:contacts] = { + count: @contacts_of_contact.count(:all), + } + @contacts_of_contact = @contacts_of_contact.paginate(:page => params[:page], :per_page => (params[:limit] || 15)) + respond_with @person else flash[:error] = I18n.t 'people.show.does_not_exist' redirect_to people_path @@ -167,8 +176,9 @@ class PeopleController < ApplicationController @contact = current_user.contact_for(@person) || Contact.new @aspect = :profile if params[:create] # let aspect dropdown create new aspects bootstrap = params[:bootstrap] || false + size = params[:size] || "small" - render :partial => 'aspect_membership_dropdown', :locals => {:contact => @contact, :person => @person, :hang => 'left', :bootstrap => bootstrap} + render :partial => 'aspect_membership_dropdown', :locals => {:contact => @contact, :person => @person, :hang => 'left', :bootstrap => bootstrap, :size => size} end private @@ -218,20 +228,6 @@ class PeopleController < ApplicationController end.order('created_at desc') end - # given a `@person` find the contacts that person has in that aspect(?) - # or use your own contacts if it's yourself - # see: `Contact#contacts` - def contact_contacts - return Contact.none unless user_signed_in? - - @contact_contacts ||= if @person == current_user.person - current_user.contact_people - else - contact = current_user.contact_for(@person) - contact.try(:contacts) || Contact.none - end - end - def mark_corresponding_notifications_read Notification.where(recipient_id: current_user.id, target_type: "Person", target_id: @person.id, unread: true).each do |n| n.set_read_state( true ) diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index bce6c78656..8a55700d36 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -5,6 +5,8 @@ class PhotosController < ApplicationController before_action :authenticate_user!, :except => :show + layout ->(c){ request.format == :mobile ? "application" : "with_header_with_footer" } + use_bootstrap_for :index respond_to :html, :json def show @@ -23,21 +25,20 @@ class PhotosController < ApplicationController if @person @contact = current_user.contact_for(@person) - - if @contact - @contacts_of_contact = @contact.contacts - @contacts_of_contact_count = @contact.contacts.count(:all) - else - @contact = Contact.new - end - - @posts = current_user.photos_from(@person, max_time: max_time) - + @posts = current_user.photos_from(@person, max_time: max_time).order('created_at desc') respond_to do |format| - format.all { render 'people/show' } + format.all do + gon.preloads[:person] = PersonPresenter.new(@person, current_user).full_hash_with_profile + gon.preloads[:photos] = { + count: @posts.count(:all), + } + gon.preloads[:contacts] = { + count: Contact.contact_contacts_for(current_user, @person).count(:all), + } + render 'people/show' + end format.json{ render_for_api :backbone, :json => @posts, :root => :photos } end - else flash[:error] = I18n.t 'people.show.does_not_exist' redirect_to people_path diff --git a/app/helpers/aspect_global_helper.rb b/app/helpers/aspect_global_helper.rb index fa47ccc05c..5f8f0d9caa 100644 --- a/app/helpers/aspect_global_helper.rb +++ b/app/helpers/aspect_global_helper.rb @@ -3,7 +3,7 @@ # the COPYRIGHT file. module AspectGlobalHelper - def aspect_membership_dropdown(contact, person, hang, aspect=nil, force_bootstrap=false) + def aspect_membership_dropdown(contact, person, hang, aspect=nil, force_bootstrap=false, size="small") aspect_membership_ids = {} selected_aspects = all_aspects.select{|aspect| contact.in_aspect?(aspect)} @@ -12,13 +12,26 @@ module AspectGlobalHelper aspect_membership_ids[a.id] = record.id end + button_class = selected_aspects.size>0 ? "green" : "btn-default" + button_class << case size + when "small" + " btn-small" + when "normal" + "" + when "large" + " btn-large" + else + rase ArgumentError, "unknown size #{size}" + end + if bootstrap? || force_bootstrap render "aspect_memberships/aspect_membership_dropdown", :selected_aspects => selected_aspects, :aspect_membership_ids => aspect_membership_ids, :person => person, :hang => hang, - :dropdown_class => "aspect_membership" + :dropdown_class => "aspect_membership", + :button_class => button_class else render "aspect_memberships/aspect_membership_dropdown_blueprint", :selected_aspects => selected_aspects, diff --git a/app/helpers/contacts_helper.rb b/app/helpers/contacts_helper.rb index 379a073dfb..5ea96b5a26 100644 --- a/app/helpers/contacts_helper.rb +++ b/app/helpers/contacts_helper.rb @@ -24,11 +24,11 @@ module ContactsHelper def start_a_conversation_link(aspect, contacts_size) suggested_limit = 16 - conv_opts = { class: "conversation_button", rel: "facebox"} + conv_opts = { class: "conversation_button contacts_button"} conv_opts[:title] = t('.many_people_are_you_sure', suggested_limit: suggested_limit) if contacts_size > suggested_limit - link_to new_conversation_path(aspect_id: aspect.id, name: aspect.name, facebox: true), conv_opts do - content_tag(:i, nil, :class => 'entypo mail contacts-header-icon', :title => t('contacts.index.start_a_conversation')) + content_tag :span, conv_opts do + content_tag(:i, nil, :class => 'entypo mail contacts-header-icon', :title => t('contacts.index.start_a_conversation'), 'data-toggle' => 'modal', 'data-target' => '#conversationModal') end end end diff --git a/app/helpers/people_helper.rb b/app/helpers/people_helper.rb index 75a63cd883..63d39af211 100644 --- a/app/helpers/people_helper.rb +++ b/app/helpers/people_helper.rb @@ -77,30 +77,4 @@ module PeopleHelper return Rails.application.routes.url_helpers.person_path(person, opts) end end - - def sharing_message(person, contact) - if contact.sharing? - content_tag(:div, :class => 'sharing_message_container', :title => I18n.t('people.helper.is_sharing', :name => person.name)) do - content_tag(:div, nil, :class => 'icons-check_yes_ok', :id => 'sharing_message') - end - else - content_tag(:div, :class => 'sharing_message_container', :title => I18n.t('people.helper.is_not_sharing', :name => person.name)) do - content_tag(:div, nil, :class => 'icons-circle', :id => 'sharing_message') - end - end - end - - def profile_buttons_class(contact, block) - if block.present? - 'blocked' - elsif contact.mutual? - 'mutual' - elsif contact.sharing? - 'sharing' - elsif contact.receiving? - 'receiving' - else - 'not_sharing' - end - end end diff --git a/app/models/contact.rb b/app/models/contact.rb index 1d77557841..861ec07715 100644 --- a/app/models/contact.rb +++ b/app/models/contact.rb @@ -89,6 +89,17 @@ class Contact < ActiveRecord::Base end end + def self.contact_contacts_for(user, person) + return none unless user + + if person == user.person + user.contact_people + else + contact = user.contact_for(person) + contact.try(:contacts) || none + end + end + private def not_contact_with_closed_account if person_id && person.closed_account? diff --git a/app/views/aspect_memberships/_aspect_membership_dropdown.html.haml b/app/views/aspect_memberships/_aspect_membership_dropdown.html.haml index 7d1cab891c..04650a4d86 100644 --- a/app/views/aspect_memberships/_aspect_membership_dropdown.html.haml +++ b/app/views/aspect_memberships/_aspect_membership_dropdown.html.haml @@ -1,5 +1,5 @@ .btn-group.aspect_dropdown.aspect_membership_dropdown - %button.btn.btn-small.dropdown-toggle{:class => selected_aspects.size>0 ? "green" : "btn-default", "data-toggle" => "dropdown", :tabindex => '0'} + %button.btn.dropdown-toggle{:class => button_class, "data-toggle" => "dropdown", :tabindex => '0'} %span.text - if selected_aspects.size == all_aspects.size = t('all_aspects') diff --git a/app/views/contacts/_header.html.haml b/app/views/contacts/_header.html.haml index 1d3ec7e463..ef49831fa8 100644 --- a/app/views/contacts/_header.html.haml +++ b/app/views/contacts/_header.html.haml @@ -4,20 +4,20 @@ - if @contacts_size > 0 && @contacts_size < 20 = start_a_conversation_link(@aspect, @contacts_size) - = link_to aspect_toggle_contact_visibility_path(@aspect), id: "contacts_visibility_toggle", method: :put, remote: true do + = link_to aspect_toggle_contact_visibility_path(@aspect), id: "contacts_visibility_toggle", class: "contacts_button", method: :put, remote: true do -if @aspect.contacts_visible? %i.entypo.lock-open.contacts-header-icon{:title => t('aspects.edit.aspect_list_is_visible')} -else %i.entypo.lock.contacts-header-icon{:title => t('aspects.edit.aspect_list_is_not_visible')} - = link_to @aspect, method: "delete", data: { confirm: t('aspects.edit.confirm_remove_aspect') }, class: 'delete', id: 'delete_aspect' do + = link_to @aspect, method: "delete", data: { confirm: t('aspects.edit.confirm_remove_aspect') }, class: 'delete contacts_button', id: 'delete_aspect' do %i.entypo.trash.contacts-header-icon{:title => t('delete')} .pull-right = search_field_tag :contact_search, "", id: "contact_list_search", class: "search-query", placeholder: t('contacts.index.user_search') %h3 %span#aspect_name = @aspect.name - %span#change_aspect_name + %span#change_aspect_name.contacts_button %i.entypo.pencil.contacts-header-icon{:title => t('aspects.edit.rename')} #aspect_name_form = form_for @aspect, :remote => true do |aspect| @@ -33,4 +33,3 @@ = t('contacts.index.all_contacts') - else = t('contacts.index.my_contacts') - diff --git a/app/views/contacts/index.html.haml b/app/views/contacts/index.html.haml index 4878f1da5f..6bf43a5131 100644 --- a/app/views/contacts/index.html.haml +++ b/app/views/contacts/index.html.haml @@ -20,3 +20,10 @@ %p != t('.no_contacts_message', :community_spotlight => link_to(t('.community_spotlight'), community_spotlight_path)) + +-if @aspect + #new_conversation_pane + = render 'shared/modal', + :path => new_conversation_path(:aspect_id => @aspect.id, :name => @aspect.name, :modal => true), + :title => t('conversations.index.new_conversation'), + :id => 'conversationModal' diff --git a/app/views/conversations/new.html.haml b/app/views/conversations/new.html.haml new file mode 100644 index 0000000000..8462a39900 --- /dev/null +++ b/app/views/conversations/new.html.haml @@ -0,0 +1,11 @@ +:javascript + $(document).ready(function () { + var data = $.parseJSON( "#{escape_javascript(@contacts_json)}" ); + new app.views.ConversationsForm({ + contacts: data, + prefillName: "#{h params[:name]}", + prefillValue: "#{@contact_ids}" + }); + }); + += render 'conversations/new' diff --git a/app/views/conversations/new.haml b/app/views/conversations/new.mobile.haml similarity index 93% rename from app/views/conversations/new.haml rename to app/views/conversations/new.mobile.haml index 4d65275cdb..59ea5328a8 100644 --- a/app/views/conversations/new.haml +++ b/app/views/conversations/new.mobile.haml @@ -2,9 +2,8 @@ -# licensed under the Affero General Public License version 3 or later. See -# the COPYRIGHT file. -- if in_mobile_view? - = javascript_include_tag :jquery - = javascript_include_tag :mobile += javascript_include_tag :jquery += javascript_include_tag :mobile :javascript $(document).ready(function () { diff --git a/app/views/notifications/index.html.haml b/app/views/notifications/index.html.haml index 19033fe7ac..541d030aa4 100644 --- a/app/views/notifications/index.html.haml +++ b/app/views/notifications/index.html.haml @@ -20,11 +20,12 @@ - when 'liked' %i.entypo.heart - when 'mentioned' - %i.entypo.pencil + %span.mentionIcon + @ - when 'reshared' %i.entypo.retweet - when 'started_sharing' - %i.entypo.users + %i.entypo.add-user = t('.'+key) .span9.stream.notifications diff --git a/app/views/people/_aspect_membership_dropdown.haml b/app/views/people/_aspect_membership_dropdown.haml index 7efd9f1f3f..5bd80d4b3c 100644 --- a/app/views/people/_aspect_membership_dropdown.haml +++ b/app/views/people/_aspect_membership_dropdown.haml @@ -1 +1 @@ -= aspect_membership_dropdown(@contact, @person, 'left', nil, bootstrap) += aspect_membership_dropdown(@contact, @person, 'right', nil, bootstrap, size) diff --git a/app/views/people/_profile_sidebar.html.haml b/app/views/people/_profile_sidebar.html.haml deleted file mode 100644 index aedc740d34..0000000000 --- a/app/views/people/_profile_sidebar.html.haml +++ /dev/null @@ -1,90 +0,0 @@ --# Copyright (c) 2010-2011, Diaspora Inc. This file is --# licensed under the Affero General Public License version 3 or later. See --# the COPYRIGHT file. - - -.badge - .profile_photo - = person_image_link(person, :size => :thumb_large, :to => :photos) - - - if user_signed_in? - - if person != current_user.person - %div#profile_buttons{ :class => profile_buttons_class(@contact, @block) } - = sharing_message(@person, @contact) - - - if @contact.receiving? - .profile_button - = link_to content_tag(:div, nil, :class => 'icons-mention', :title => t('people.show.mention'), :id => 'mention_button'), new_status_message_path(:person_id => @person.id), :rel => 'facebox' - .white_bar - - - if @contact.mutual? - - - .profile_button - = link_to content_tag(:div, nil, :class => 'icons-message', :title => t('people.show.message'), :id => 'message_button'), new_conversation_path(:contact_id => @contact.id, :name => @contact.person.name, :facebox => true), :rel => 'facebox' - .white_bar - - .profile_button - = link_to content_tag(:div, nil, :class => 'icons-ignoreuser block_user', :title => t('ignore'), :id => 'block_user_button', :data => { :person_id => @person.id }), '#', :rel => "nofollow" if @block.blank? - --if user_signed_in? && (contact.sharing? || person == current_user.person) - %ul#profile_information - - - unless person.bio.blank? - %li - %h4 - =t('.bio') - %div{ :class => direction_for(person.bio) } - = person.profile.bio_message.markdownified - - unless person.profile.location.blank? - %li - %h4 - =t('.location') - %div{ :class => direction_for(person.location) } - = person.profile.location_message.markdownified - - - unless person.gender.blank? - %li - %h4 - =t('.gender') - = person.gender - - - unless person.birthday.blank? - %li - %h4 - =t('.born') - = birthday_format(person.birthday) - - if @photos.present? - %li.image_list - %h4 - = t('.photos') - .item_count - = "#{@photos.count(:all)}" - - @photos.limit(8).each do |photo| - = image_tag(photo.url(:thumb_small)) - %br - = link_to t('layouts.header.view_all'), person_photos_path(person) - - - if person == current_user.person - %li.image_list - %h4 - = t('_contacts') - .item_count - = all_contacts_count - .section.contact_pictures - - current_user.contacts.limit(8).each do |contact| - = person_image_link contact.person, :size => :thumb_small - %p.see_all= link_to t('layouts.header.view_all'), contacts_path - - elsif @contact.persisted? && @contacts_of_contact_count > 0 - %li.image_list - %h4 - = t('_contacts') - .item_count - = @contacts_of_contact_count - .section.contact_pictures - -@contacts_of_contact.limit(8).each do |person| - = person_image_link person, :size => :thumb_small - %p.see_all= link_to t('layouts.header.view_all'), person_contacts_path(@person) - - %br - %br diff --git a/app/views/people/_sub_header.html.haml b/app/views/people/_sub_header.html.haml deleted file mode 100644 index 4aef4bd72f..0000000000 --- a/app/views/people/_sub_header.html.haml +++ /dev/null @@ -1,34 +0,0 @@ -#author_info - .right - - if user_signed_in? && current_user.person != person - - if @block.present? - = link_to t('users.privacy_settings.stop_ignoring'), block_path(@block), - :method => :delete, - :class => "button" - - - else - = aspect_membership_dropdown(contact, person, 'right') - - elsif user_signed_in? && current_user.person == person - = link_to t('people.profile_sidebar.edit_my_profile'), edit_profile_path, :class => 'button creation' - - %h2 - = person.name - %span.diaspora_handle - = person.diaspora_handle - - .description - - if !person.tag_string.blank? && user_signed_in? - = Diaspora::Taggable.format_tags(person.profile.tag_string) - - if person == current_user.person - %span.hover_edit - = link_to t('.edit'), edit_profile_path - - else - - if user_signed_in? && person == current_user.person - %i - = t('.you_have_no_tags') - %span.add_tags - = link_to t('.add_some'), edit_profile_path - - if user_signed_in? && current_page?(person_path current_user.person) - %hr - = render 'aspects/aspect_stream', :stream => @stream -%hr diff --git a/app/views/people/contacts.haml b/app/views/people/contacts.haml index c53f157818..90d89e6eb0 100644 --- a/app/views/people/contacts.haml +++ b/app/views/people/contacts.haml @@ -1,21 +1,41 @@ --# Copyright (c) 2010-2011, Diaspora Inc. This file is --# licensed under the Affero General Public License version 3 or later. See --# the COPYRIGHT file. - - +-# TODO this should happen in the js app - content_for :head do - = javascript_include_tag :people + - if user_signed_in? && @person != current_user.person + :javascript + Mentions.options.prefillMention = Mentions._contactToMention(#{j @person.to_json}); - content_for :page_title do = @person.name -.span-6 - = render :partial => 'people/profile_sidebar', :locals => {:person => @person, :contact => @contact } +.container-fluid#profile_container + .row-fluid + .span3 + #profile + -# here be JS + + .span9 + .profile_header + -# more JS + + .stream_container + #people_stream.stream + - @hashes.each do |hash| + = render :partial => 'people/person', :locals => hash + = will_paginate @contacts_of_contact + + %a{:id=>"back-to-top", :title=>"#{t('layouts.application.back_to_top')}", :href=>"#"} + ⇧ -.span-18.last - = render 'people/sub_header', :person => @person, :contact => @contact +-if user_signed_in? && @person + #new_status_message_pane + = render 'shared/modal', + :path => new_status_message_path(:person_id => @person.id), + :title => t('status_messages.new.mentioning', :person => @person.name), + :id => 'mentionModal' - #people_stream.stream - - @hashes.each do |hash| - = render :partial => 'people/person', :locals => hash - = will_paginate @contacts_of_contact + -if @contact + #new_conversation_pane + = render 'shared/modal', + :path => new_conversation_path(:contact_id => @contact.id, :name => @contact.person.name, :modal => true), + :title => t('conversations.index.new_conversation'), + :id => 'conversationModal' diff --git a/app/views/people/show.html.haml b/app/views/people/show.html.haml index 937cb4bd40..235c22ccc3 100644 --- a/app/views/people/show.html.haml +++ b/app/views/people/show.html.haml @@ -2,7 +2,7 @@ -# licensed under the Affero General Public License version 3 or later. See -# the COPYRIGHT file. - +-# TODO this should happen in the js app - content_for :head do - if user_signed_in? && @person != current_user.person :javascript @@ -11,24 +11,40 @@ - content_for :page_title do = @person.name -.span-6 - #profile - -# here be JS +.container-fluid#profile_container + .row-fluid + .span3 + #profile + -# here be JS + + .span9 + .profile_header + -# more JS + + .stream_container -.span-18.last - .profile_header - -# more JS + -if user_signed_in? && current_page?(person_path(current_user.person)) + = render 'publisher/publisher', publisher_aspects_for(nil) - .stream_container + #main_stream.stream + -# JS - -if user_signed_in? && current_page?(person_path(current_user.person)) - = render 'publisher/publisher', publisher_aspects_for(nil) + #paginate + %span.loader.hidden - #main_stream.stream - -# JS + %a{:id=>"back-to-top", :title=>"#{t('layouts.application.back_to_top')}", :href=>"#"} + ⇧ - #paginate - %span.loader.hidden +-if user_signed_in? && @person + #new_status_message_pane + = render 'shared/modal', + :path => new_status_message_path(:person_id => @person.id), + :title => t('status_messages.new.mentioning', :person => @person.name), + :id => 'mentionModal' - %a{:id=>"back-to-top", :title=>"#{t('layouts.application.back_to_top')}", :href=>"#"} - ⇧ + -if @contact + #new_conversation_pane + = render 'shared/modal', + :path => new_conversation_path(:contact_id => @contact.id, :name => @contact.person.name, :modal => true), + :title => t('conversations.index.new_conversation'), + :id => 'conversationModal' diff --git a/app/views/status_messages/new.html.haml b/app/views/status_messages/new.html.haml index 44a50b7bda..1e60089442 100644 --- a/app/views/status_messages/new.html.haml +++ b/app/views/status_messages/new.html.haml @@ -1,21 +1,19 @@ --# Copyright (c) 2010-2011, Diaspora Inc. This file is --# licensed under the Affero General Public License version 3 or later. See --# the COPYRIGHT file. - = javascript_include_tag :home -#new_status_message_pane - .span-15.last - #facebox_header - %h3 - = t('.mentioning', :person => @person.name) - - = render :partial => 'publisher/publisher', :locals => { :aspect => @aspect, :aspect_ids => @aspect_ids, :selected_aspects => @aspects_with_person, :person => @person} += render :partial => 'publisher/publisher_bootstrap', + :locals => { :aspect => @aspect, + :aspect_ids => @aspect_ids, + :selected_aspects => @aspects_with_person, + :person => @person } :javascript $(function() { app.publisher = new app.views.Publisher({ standalone: true }); - $("#publisher").bind('ajax:success', function(){ location.reload(); }); + app.publisher.open(); + $("#publisher").bind('ajax:success', function(){ + $("#mentionModal").modal('hide'); + location.reload(); + }); }); diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml index e84e0b4a8f..57b5da00bd 100644 --- a/config/locales/javascript/javascript.en.yml +++ b/config/locales/javascript/javascript.en.yml @@ -134,6 +134,7 @@ en: born: "Birthday" photos: "Photos" contacts: "Contacts" + posts: "Posts" conversation: participants: "Participants" diff --git a/features/desktop/connects_users.feature b/features/desktop/connects_users.feature index efa6f4a05c..e90c5cbda5 100644 --- a/features/desktop/connects_users.feature +++ b/features/desktop/connects_users.feature @@ -83,7 +83,7 @@ Feature: following and being followed When I sign in as "alice@alice.alice" And I am on "bob@bob.bob"'s page - And I press the first ".toggle.button" + And I press the first ".aspect_membership_dropdown .dropdown-toggle" And I press the first "a" within ".add_aspect" And I fill in "Name" with "Super People" in the modal window @@ -101,16 +101,16 @@ Feature: following and being followed And I am on "alice@alice.alice"'s page Then I should see "Besties" - Then I should see a "#mention_button" within "#profile" - Then I should not see a "#message_button" within "#profile" + Then I should see a "#mention_button" within "#profile_buttons" + Then I should not see a "#message_button" within "#profile_buttons" Scenario: interacting with the profile page of someone who follows you but who you do not follow Given I sign in as "alice@alice.alice" And I am on "bob@bob.bob"'s page Then I should see "Add contact" - Then I should not see a "#mention_button" within "#profile" - Then I should not see a "#message_button" within "#profile" + Then I should not see a "#mention_button" within "#profile_buttons" + Then I should not see a "#message_button" within "#profile_buttons" Scenario: interacting with the profile page of someone you follow who also follows you Given I sign in as "alice@alice.alice" @@ -121,5 +121,5 @@ Feature: following and being followed When I go to "bob@bob.bob"'s page Then I should see "All Aspects" - Then I should see a "#mention_button" within "#profile" - Then I should see a "#message_button" within "#profile" + Then I should see a "#mention_button" within "#profile_buttons" + Then I should see a "#message_button" within "#profile_buttons" diff --git a/features/desktop/contacts.feature b/features/desktop/contacts.feature index 33639826eb..97bc87a1bd 100644 --- a/features/desktop/contacts.feature +++ b/features/desktop/contacts.feature @@ -13,8 +13,8 @@ Feature: show contacts Scenario: see own contacts on profile When I am on "robert@grimm.grimm"'s page - And I press the first "a" within ".section.contact_pictures" - Then I should see "Alice Smith" + And I press the first "#contacts_link" + Then I should be on the contacts page Scenario: see contacts of a visible aspect list When I am on "bob@bob.bob"'s page @@ -22,7 +22,10 @@ Feature: show contacts And I sign out And I sign in as "alice@alice.alice" And I am on "robert@grimm.grimm"'s page - And I press the first "a" within ".section.contact_pictures" + Then I should see "Contacts" within "#profile_horizontal_bar" + + When I press the first "#contacts_link" + And I press the first "a" within "#people_stream .media-body" Then I should see "Bob Jones" Scenario: don't see contacts of an invisible aspect list @@ -35,4 +38,4 @@ Feature: show contacts And I sign in as "alice@alice.alice" And I am on "robert@grimm.grimm"'s page - Then I should not see "Contacts" within "#profile_information" + Then I should not see "Contacts" within "#profile_horizontal_bar" diff --git a/features/desktop/mentions_from_profile_page.feature b/features/desktop/mentions_from_profile_page.feature index b999523f0b..962e8c5e79 100644 --- a/features/desktop/mentions_from_profile_page.feature +++ b/features/desktop/mentions_from_profile_page.feature @@ -23,10 +23,9 @@ Feature: mentioning a contact from their profile page Scenario: mentioning while posting to all aspects Given I am on "alice@alice.alice"'s page - And I have turned off jQuery effects And I want to mention her from the profile And I append "I am eating a yogurt" to the publisher - And I press "Share" in the modal window + And I press "Share" in the mention modal When I am on the aspects page And I follow "PostingTo" within "#aspects_list" Then I should see "I am eating a yogurt" @@ -37,13 +36,12 @@ Feature: mentioning a contact from their profile page Scenario: mentioning while posting to just one aspect Given I am on "alice@alice.alice"'s page - And I have turned off jQuery effects And I want to mention her from the profile - And I press the aspect dropdown in the modal window - And I toggle the aspect "NotPostingThingsHere" in the modal window - And I press the aspect dropdown in the modal window + And I press the aspect dropdown in the mention modal + And I toggle the aspect "NotPostingThingsHere" in the mention modal + And I press the aspect dropdown in the mention modal And I append "I am eating a yogurt" to the publisher - And I press "Share" in the modal window + And I press "Share" in the mention modal When I am on the aspects page And I select only "PostingTo" aspect diff --git a/features/desktop/profile_photos.feature b/features/desktop/profile_photos.feature index 2d7dc10bc5..275e31b32d 100644 --- a/features/desktop/profile_photos.feature +++ b/features/desktop/profile_photos.feature @@ -10,27 +10,25 @@ Feature: show photos And I sign in as "robert@grimm.grimm" Given I expand the publisher - And I have turned off jQuery effects - And I attach the file "spec/fixtures/button.png" to hidden "file" within "#file-upload" - And I press "Share" + And I have turned off jQuery effects + And I attach the file "spec/fixtures/button.png" to hidden "file" within "#file-upload" + And I press "Share" Scenario: see my own photos When I am on "robert@grimm.grimm"'s page #TODO: find out why images don't show on first load And I am on "robert@grimm.grimm"'s page - And I follow "View all" within ".image_list" + And I press the first "#photos_link" Then I should be on person_photos page Scenario: I cannot see photos of people who don't share with me When I sign in as "alice@alice.alice" And I am on "robert@grimm.grimm"'s page - Then I should not see "photos" within "div#profile" + Then I should not see "Photos" within "#profile_horizontal_bar" - Scenario: I delete a photo - Given I am on "robert@grimm.grimm"'s photos page - When I delete a photo - And I confirm the alert - Then I should not see "photos" within "div#profile" - - + When I am on "robert@grimm.grimm"'s photos page + And I delete a photo + And I confirm the alert + And I am on "robert@grimm.grimm"'s page + Then I should not see "Photos" within "#profile_horizontal_bar" diff --git a/features/step_definitions/aspects_steps.rb b/features/step_definitions/aspects_steps.rb index e0f827f4ae..ad0234174d 100644 --- a/features/step_definitions/aspects_steps.rb +++ b/features/step_definitions/aspects_steps.rb @@ -1,19 +1,21 @@ module AspectCukeHelpers def click_aspect_dropdown - find('.dropdown .button').click + # blueprint: .dropdown .button, bootstrap: .aspect_dropdown .dropdown-toggle + find('.dropdown .button, .aspect_dropdown .dropdown-toggle').click end def toggle_aspect(a_name) + # blueprint: .dropdown li, bootstrap: .aspect_dropdown li a_id = @me.aspects.where(name: a_name).pluck(:id).first - aspect_css = ".dropdown li[data-aspect_id='#{a_id}']" + aspect_css = ".dropdown li[data-aspect_id='#{a_id}'], .aspect_dropdown li[data-aspect_id='#{a_id}']" expect(page).to have_selector(aspect_css) find(aspect_css).click end def toggle_aspect_via_ui(aspect_name) - aspects_dropdown = find(".aspect_membership .toggle.button", match: :first) + aspects_dropdown = find(".aspect_membership_dropdown .dropdown-toggle", match: :first) aspects_dropdown.click - aspect = find(".dropdown.active .dropdown_list li", text: aspect_name) + aspect = find(".aspect_membership_dropdown.open .dropdown-menu li", text: aspect_name) aspect.click aspect.parent.should have_no_css(".loading") diff --git a/features/step_definitions/custom_web_steps.rb b/features/step_definitions/custom_web_steps.rb index e74f7168f5..ca82cdcf6c 100644 --- a/features/step_definitions/custom_web_steps.rb +++ b/features/step_definitions/custom_web_steps.rb @@ -74,7 +74,7 @@ end And /^I want to mention (?:him|her) from the profile$/ do find('#mention_button').click - within('#facebox') do + within('#mentionModal') do click_publisher end end @@ -130,6 +130,12 @@ When /^(.*) in the modal window$/ do |action| end end +When /^(.*) in the mention modal$/ do |action| + within('#mentionModal') do + step action + end +end + When /^I press the first "([^"]*)"(?: within "([^"]*)")?$/ do |link_selector, within_selector| with_scope(within_selector) do current_scope.find(link_selector, match: :first).click diff --git a/features/step_definitions/posts_steps.rb b/features/step_definitions/posts_steps.rb index 0bcb3ef342..69c86f80b0 100644 --- a/features/step_definitions/posts_steps.rb +++ b/features/step_definitions/posts_steps.rb @@ -93,7 +93,7 @@ end When /^I select "([^"]*)" on the aspect dropdown$/ do |text| page.execute_script( - "$('#publisher .dropdown .dropdown_list') + "$('#publisher .dropdown .dropdown_list, #publisher .aspect_dropdown .dropdown-menu') .find('li').each(function(i,el){ var elem = $(el); if ('" + text + "' == $.trim(elem.text()) ) { diff --git a/features/support/paths.rb b/features/support/paths.rb index adc69649ee..0f5bf7ba20 100644 --- a/features/support/paths.rb +++ b/features/support/paths.rb @@ -28,8 +28,8 @@ module NavigationHelpers when /^"([^\"]*)"'s page$/ p = User.find_by_email($1).person { path: person_path(p), - # '.diaspora_handle' on desktop, '.description' on mobile - special_elem: { selector: '.diaspora_handle, .description', text: p.diaspora_handle } + # '#diaspora_handle' on desktop, '.description' on mobile + special_elem: { selector: '#diaspora_handle, .description', text: p.diaspora_handle } } when /^"([^\"]*)"'s photos page$/ p = User.find_by_email($1).person diff --git a/spec/controllers/conversations_controller_spec.rb b/spec/controllers/conversations_controller_spec.rb index 60f363e93b..ae07609fce 100644 --- a/spec/controllers/conversations_controller_spec.rb +++ b/spec/controllers/conversations_controller_spec.rb @@ -16,33 +16,33 @@ describe ConversationsController, :type => :controller do end end - describe '#new facebox' do + describe '#new modal' do it 'succeeds' do - get :new, :facebox => true + get :new, :modal => true expect(response).to be_success end it "assigns a json list of contacts that are sharing with the person" do - get :new, :facebox => true + get :new, :modal => true expect(assigns(:contacts_json)).to include(alice.contacts.where(:sharing => true).first.person.name) alice.contacts << Contact.new(:person_id => eve.person.id, :user_id => alice.id, :sharing => false, :receiving => true) expect(assigns(:contacts_json)).not_to include(alice.contacts.where(:sharing => false).first.person.name) end it "assigns a contact if passed a contact id" do - get :new, :contact_id => alice.contacts.first.id, :facebox => true + get :new, :contact_id => alice.contacts.first.id, :modal => true expect(assigns(:contact_ids)).to eq(alice.contacts.first.id) end it "assigns a set of contacts if passed an aspect id" do - get :new, :aspect_id => alice.aspects.first.id, :facebox => true + get :new, :aspect_id => alice.aspects.first.id, :modal => true expect(assigns(:contact_ids)).to eq(alice.aspects.first.contacts.map(&:id).join(',')) end it "does not allow XSS via the name parameter" do ["</script><script>alert(1);</script>", '"}]});alert(1);(function f() {var foo = [{b:"'].each do |xss| - get :new, :facebox => true, name: xss + get :new, :modal => true, name: xss expect(response.body).not_to include xss end end @@ -51,7 +51,7 @@ describe ConversationsController, :type => :controller do xss = "<script>alert(0);</script>" contact = alice.contacts.first contact.person.profile.update_attribute(:first_name, xss) - get :new, :facebox => true + get :new, :modal => true json = JSON.parse(assigns(:contacts_json)).first expect(json['value'].to_s).to eq(contact.id.to_s) expect(json['name']).to_not include(xss) diff --git a/spec/helpers/people_helper_spec.rb b/spec/helpers/people_helper_spec.rb index 31976a4b57..6d633097df 100644 --- a/spec/helpers/people_helper_spec.rb +++ b/spec/helpers/people_helper_spec.rb @@ -101,26 +101,4 @@ describe PeopleHelper, :type => :helper do expect(local_or_remote_person_path(@person)).to eq(person_path(@person)) end end - - describe '#sharing_message' do - before do - @contact = FactoryGirl.create(:contact, :person => @person) - end - - context 'when the contact is sharing' do - it 'shows the sharing message' do - message = I18n.t('people.helper.is_sharing', :name => @person.name) - allow(@contact).to receive(:sharing?).and_return(true) - expect(sharing_message(@person, @contact)).to include(message) - end - end - - context 'when the contact is not sharing' do - it 'does show the not sharing message' do - message = I18n.t('people.helper.is_not_sharing', :name => @person.name) - allow(@contact).to receive(:sharing?).and_return(false) - expect(sharing_message(@person, @contact)).to include(message) - end - end - end end diff --git a/spec/javascripts/app/views/profile_header_view_spec.js b/spec/javascripts/app/views/profile_header_view_spec.js index 82a746c2d1..724cc72600 100644 --- a/spec/javascripts/app/views/profile_header_view_spec.js +++ b/spec/javascripts/app/views/profile_header_view_spec.js @@ -4,9 +4,11 @@ describe("app.views.ProfileHeader", function() { this.model = factory.personWithProfile({ diaspora_id: "my@pod", name: "User Name", + relationship: 'mutual', profile: { tags: ['test'] } }); this.view = new app.views.ProfileHeader({model: this.model}); + loginAs(factory.userAttrs()); }); context("#presenter", function() { @@ -17,6 +19,11 @@ describe("app.views.ProfileHeader", function() { is_blocked: false, is_own_profile: false, has_tags: true, + show_profile_btns: true, + relationship: 'mutual', + is_sharing: true, + is_receiving: true, + is_mutual: true, profile: jasmine.objectContaining({ tags: ['test'] }) diff --git a/spec/javascripts/app/views/profile_sidebar_view_spec.js b/spec/javascripts/app/views/profile_sidebar_view_spec.js index d241dc7cec..7a6e7e055b 100644 --- a/spec/javascripts/app/views/profile_sidebar_view_spec.js +++ b/spec/javascripts/app/views/profile_sidebar_view_spec.js @@ -24,12 +24,7 @@ describe("app.views.ProfileSidebar", function() { console.log(this.view.presenter()); expect(this.view.presenter()).toEqual(jasmine.objectContaining({ relationship: 'mutual', - do_profile_btns: true, - do_profile_info: true, - is_sharing: true, - is_receiving: true, - is_mutual: true, - is_not_blocked: true, + show_profile_info: true, profile: jasmine.objectContaining({ bio: "confidential", location: "underground", diff --git a/spec/javascripts/app/views/publisher_view_spec.js b/spec/javascripts/app/views/publisher_view_spec.js index 2a86fce7cc..87eda31166 100644 --- a/spec/javascripts/app/views/publisher_view_spec.js +++ b/spec/javascripts/app/views/publisher_view_spec.js @@ -247,8 +247,8 @@ describe("app.views.Publisher", function() { spec.loadFixture('status_message_new'); Diaspora.I18n.load({ stream: { public: 'Public' }}); - this.radio_els = $('#publisher .dropdown li.radio'); - this.check_els = $('#publisher .dropdown li.aspect_selector'); + this.radio_els = $('#publisher .aspect_dropdown li.radio'); + this.check_els = $('#publisher .aspect_dropdown li.aspect_selector'); this.visibility_icon = $('#visibility-icon'); this.view = new app.views.Publisher(); @@ -310,8 +310,8 @@ describe("app.views.Publisher", function() { describe("hidden form elements", function(){ beforeEach(function(){ - this.li = $('<li data-aspect_id="42" />'); - this.view.$('.dropdown_list').append(this.li); + this.li = $('<li data-aspect_id="42" class="aspect_selector" />'); + this.view.$('.dropdown-menu').append(this.li); }); it("removes a previous selection and inserts the current one", function() { @@ -337,8 +337,8 @@ describe("app.views.Publisher", function() { }); it("keeps other fields with different values", function() { - var li2 = $("<li data-aspect_id=99></li>"); - this.view.$('.dropdown_list').append(li2); + var li2 = $('<li data-aspect_id=99 class="aspect_selector"></li>'); + this.view.$('.dropdown-menu').append(li2); this.li.trigger('click'); li2.trigger('click'); -- GitLab