diff options
author | Florian Staudacher <florian_staudacher@yahoo.de> | 2014-10-06 17:09:08 +0400 |
---|---|---|
committer | Florian Staudacher <florian_staudacher@yahoo.de> | 2014-10-06 17:09:08 +0400 |
commit | 4f87a47d0a012ced09455ac58345965c0e01d0ed (patch) | |
tree | 19ded3fc967149cc38928a7e23dbd30fad5c6bf5 | |
parent | eac3f042a483851e7324f9f5721e54232d0804e0 (diff) | |
parent | 976ff0fcdadeef676837db19ce6fe6d79fa825be (diff) |
Merge pull request #4657 from svbergerem/bootstrap-people-view
Redesign profile page and port to Bootstrap
57 files changed, 537 insertions, 630 deletions
diff --git a/Changelog.md b/Changelog.md index d1454b9e1..6337c032b 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 Binary files differindex 5e134f809..026503b9a 100644 --- a/app/assets/images/icons-s729fe6854c.png +++ b/app/assets/images/icons-s71323e8d98.png diff --git a/app/assets/images/icons/circle.png b/app/assets/images/icons/circle.png Binary files differdeleted file mode 100644 index 944a88391..000000000 --- a/app/assets/images/icons/circle.png +++ /dev/null diff --git a/app/assets/javascripts/app/helpers/handlebars-helpers.js b/app/assets/javascripts/app/helpers/handlebars-helpers.js index 1be1cd98d..cea31311a 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 3aa9fb101..32298e364 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 55943e94e..df6e4ff73 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 000000000..4134a303e --- /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 c2701efa4..b697d37c1 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 971cfacce..656c3dabd 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 f45f18f33..d94871cf3 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 c7892eb34..4b7488bd0 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 376babb34..5e52dbd1a 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 681bca066..5d4e45361 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 fe872dd27..56ad441d3 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 313c72eab..72fe60ce9 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 98b38fdc3..63ccacb28 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 63858cb6b..1f3c57c42 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 f433eebf1..d93871c92 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 bf2338591..aabcb0e2e 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 2fbb51001..bcf104320 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 f40c606bf..16c29e736 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 1ee8427bb..5e99f9247 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 9b2832d27..516ae8345 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 5f70552e7..69cc76d83 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 7a175d315..59c8c7496 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 f0782d70a..ff2783c6a 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 bce6c7865..8a55700d3 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 fa47ccc05..5f8f0d9ca 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 379a073df..5ea96b5a2 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 75a63cd88..63d39af21 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 1d7755784..861ec0771 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 7d1cab891..04650a4d8 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 1d3ec7e46..ef49831fa 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 4878f1da5..6bf43a513 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 000000000..8462a3990 --- /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 index 4d65275cd..59ea5328a 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 19033fe7a..541d030aa 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 7efd9f1f3..5bd80d4b3 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 aedc740d3..000000000 --- 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 4aef4bd72..000000000 --- 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 c53f15781..90d89e6eb 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 937cb4bd4..235c22ccc 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 44a50b7bd..1e6008944 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 e84e0b4a8..57b5da00b 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 efa6f4a05..e90c5cbda 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 33639826e..97bc87a1b 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 b999523f0..962e8c5e7 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 2d7dc10bc..275e31b32 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 e0f827f4a..ad0234174 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 e74f7168f..ca82cdcf6 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 0bcb3ef34..69c86f80b 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 adc69649e..0f5bf7ba2 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 60f363e93..ae07609fc 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 31976a4b5..6d633097d 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 82a746c2d..724cc7260 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 d241dc7ce..7a6e7e055 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 2a86fce7c..87eda3116 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'); |