Merge branch 'release/0.6.2.0'
This commit is contained in:
commit
241c17a814
522 changed files with 7040 additions and 5318 deletions
1
.rspec
1
.rspec
|
|
@ -3,3 +3,4 @@
|
|||
--color
|
||||
--tag ~performance
|
||||
--order random
|
||||
--require spec_helper
|
||||
|
|
|
|||
35
Changelog.md
35
Changelog.md
|
|
@ -1,3 +1,38 @@
|
|||
# 0.6.2.0
|
||||
|
||||
## Refactor
|
||||
* Use string-direction gem for rtl detection [#7181](https://github.com/diaspora/diaspora/pull/7181)
|
||||
* Reduce i18n.load side effects [#7184](https://github.com/diaspora/diaspora/pull/7184)
|
||||
* Force jasmine fails on syntax errors [#7185](https://github.com/diaspora/diaspora/pull/7185)
|
||||
* Don't display mail-related view content if it is disabled in the pod's config [#7190](https://github.com/diaspora/diaspora/pull/7190)
|
||||
* Use typeahead.js from rails-assets.org [#7192](https://github.com/diaspora/diaspora/pull/7192)
|
||||
* Refactor ShareVisibilitesController to use PostService [#7196](https://github.com/diaspora/diaspora/pull/7196)
|
||||
* Unify desktop and mobile head elements [#7194](https://github.com/diaspora/diaspora/pull/7194) [#7209](https://github.com/diaspora/diaspora/pull/7209)
|
||||
* Refactor flash messages on ajax errors for comments, likes, reshares and aspect memberships [#7202](https://github.com/diaspora/diaspora/pull/7202)
|
||||
* Only require AWS-module for fog [#7201](https://github.com/diaspora/diaspora/pull/7201)
|
||||
* Only show community spotlight links on the contacts page if community spotlight is enabled [#7213](https://github.com/diaspora/diaspora/pull/7213)
|
||||
* Require spec\_helper in .rspec [#7223](https://github.com/diaspora/diaspora/pull/7223)
|
||||
* Make the CSRF mail a bit more friendly [#7238](https://github.com/diaspora/diaspora/pull/7238) [#7241](https://github.com/diaspora/diaspora/pull/7241)
|
||||
|
||||
## Bug fixes
|
||||
* Fix fetching comments after fetching likes [#7167](https://github.com/diaspora/diaspora/pull/7167)
|
||||
* Hide 'reshare' button on already reshared posts [#7169](https://github.com/diaspora/diaspora/pull/7169)
|
||||
* Only reload profile header when changing aspect memberships [#7183](https://github.com/diaspora/diaspora/pull/7183)
|
||||
* Fix visiblity on invitation modal when opening it from the stream [#7191](https://github.com/diaspora/diaspora/pull/7191)
|
||||
* Add avatar fallback on tags page [#7198](https://github.com/diaspora/diaspora/pull/7198)
|
||||
* Update notifications when changing the stream [#7199](https://github.com/diaspora/diaspora/pull/7199)
|
||||
* Fix 500 on mobile commented and liked streams [#7219](https://github.com/diaspora/diaspora/pull/7219)
|
||||
|
||||
## Features
|
||||
* Show spinner when loading comments in the stream [#7170](https://github.com/diaspora/diaspora/pull/7170)
|
||||
* Add a dark color theme [#7152](https://github.com/diaspora/diaspora/pull/7152)
|
||||
* Added setting for custom changelog URL [#7166](https://github.com/diaspora/diaspora/pull/7166)
|
||||
* Show more information of recipients on conversation creation [#7129](https://github.com/diaspora/diaspora/pull/7129)
|
||||
* Update notifications every 5 minutes and when opening the notification dropdown [#6952](https://github.com/diaspora/diaspora/pull/6952)
|
||||
* Show browser notifications when receiving new unread notifications [#6952](https://github.com/diaspora/diaspora/pull/6952)
|
||||
* Only clear comment textarea when comment submission was successful [#7186](https://github.com/diaspora/diaspora/pull/7186)
|
||||
* Add support for graceful unicorn restarts [#7217](https://github.com/diaspora/diaspora/pull/7217)
|
||||
|
||||
# 0.6.1.0
|
||||
|
||||
Note: Although this is a minor release, the configuration file changed because the old Mapbox implementation is no longer valid, and the current implementation requires additional fields. Chances are high that if you're using the old integration, it will be broken anyway. If you do use Mapbox, please check out the `diaspora.yml.example` for new parameters.
|
||||
|
|
|
|||
8
Gemfile
8
Gemfile
|
|
@ -25,7 +25,6 @@ gem "json-schema", "2.7.0"
|
|||
|
||||
gem "devise", "4.2.0"
|
||||
gem "devise_lastseenable", "0.0.6"
|
||||
gem "devise-token_authenticatable", "0.5.2"
|
||||
|
||||
# Captcha
|
||||
|
||||
|
|
@ -73,8 +72,8 @@ gem "activerecord-import", "0.15.0"
|
|||
|
||||
# File uploading
|
||||
|
||||
gem "fog", "1.38.0", require: "fog/aws"
|
||||
gem "carrierwave", "0.11.2"
|
||||
gem "fog", "1.38.0"
|
||||
gem "mini_magick", "4.5.1"
|
||||
|
||||
# GUID generation
|
||||
|
|
@ -105,6 +104,7 @@ source "https://rails-assets.org" do
|
|||
gem "rails-assets-markdown-it-sup", "1.0.0"
|
||||
gem "rails-assets-highlightjs", "9.7.0"
|
||||
gem "rails-assets-bootstrap-markdown", "2.10.0"
|
||||
gem "rails-assets-corejs-typeahead", "1.0.1"
|
||||
|
||||
# jQuery plugins
|
||||
|
||||
|
|
@ -136,6 +136,10 @@ gem "twitter-text", "1.14.0"
|
|||
gem "ruby-oembed", "0.10.1"
|
||||
gem "open_graph_reader", "0.6.1"
|
||||
|
||||
# RTL support
|
||||
|
||||
gem "string-direction", "1.2.0"
|
||||
|
||||
# Security Headers
|
||||
|
||||
gem "secure_headers", "3.5.0"
|
||||
|
|
|
|||
11
Gemfile.lock
11
Gemfile.lock
|
|
@ -171,8 +171,6 @@ GEM
|
|||
railties (>= 4.1.0, < 5.1)
|
||||
responders
|
||||
warden (~> 1.2.3)
|
||||
devise-token_authenticatable (0.5.2)
|
||||
devise (>= 4.0.0, < 4.3.0)
|
||||
devise_lastseenable (0.0.6)
|
||||
devise
|
||||
rails (>= 3.0.4)
|
||||
|
|
@ -648,6 +646,8 @@ GEM
|
|||
rails-assets-jquery (>= 1.9.1, < 4)
|
||||
rails-assets-bootstrap-markdown (2.10.0)
|
||||
rails-assets-bootstrap (~> 3)
|
||||
rails-assets-corejs-typeahead (1.0.1)
|
||||
rails-assets-jquery (>= 1.7)
|
||||
rails-assets-diaspora_jsxc (0.1.5.develop.7)
|
||||
rails-assets-emojione (~> 2.0.1)
|
||||
rails-assets-favico.js (>= 0.3.10, < 0.4)
|
||||
|
|
@ -821,6 +821,8 @@ GEM
|
|||
activesupport (>= 3.0)
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
state_machine (1.2.0)
|
||||
string-direction (1.2.0)
|
||||
yard (~> 0.8)
|
||||
swd (1.0.1)
|
||||
activesupport (>= 3)
|
||||
attr_required (>= 0.0.5)
|
||||
|
|
@ -931,7 +933,6 @@ DEPENDENCIES
|
|||
cucumber-rails (= 1.4.5)
|
||||
database_cleaner (= 1.5.3)
|
||||
devise (= 4.2.0)
|
||||
devise-token_authenticatable (= 0.5.2)
|
||||
devise_lastseenable (= 0.0.6)
|
||||
diaspora-prosody-config (= 0.0.7)
|
||||
diaspora_federation-rails (= 0.1.5)
|
||||
|
|
@ -998,6 +999,7 @@ DEPENDENCIES
|
|||
rails-assets-autosize (= 3.0.17)!
|
||||
rails-assets-blueimp-gallery (= 2.21.3)!
|
||||
rails-assets-bootstrap-markdown (= 2.10.0)!
|
||||
rails-assets-corejs-typeahead (= 1.0.1)!
|
||||
rails-assets-diaspora_jsxc (= 0.1.5.develop.7)!
|
||||
rails-assets-highlightjs (= 9.7.0)!
|
||||
rails-assets-jasmine-ajax (= 3.2.0)!
|
||||
|
|
@ -1034,6 +1036,7 @@ DEPENDENCIES
|
|||
spring (= 2.0.0)
|
||||
spring-commands-cucumber (= 1.0.1)
|
||||
spring-commands-rspec (= 1.0.4)
|
||||
string-direction (= 1.2.0)
|
||||
test_after_commit (= 1.1.0)
|
||||
timecop (= 0.8.1)
|
||||
turbo_dev_assets (= 0.0.2)
|
||||
|
|
@ -1049,4 +1052,4 @@ DEPENDENCIES
|
|||
will_paginate (= 3.1.5)
|
||||
|
||||
BUNDLED WITH
|
||||
1.13.5
|
||||
1.13.6
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ var app = {
|
|||
|
||||
setupHeader: function() {
|
||||
if(app.currentUser.authenticated()) {
|
||||
app.notificationsCollection = new app.collections.Notifications();
|
||||
app.header = new app.views.Header();
|
||||
$("header").prepend(app.header.el);
|
||||
app.header.render();
|
||||
|
|
@ -114,6 +115,7 @@ var app = {
|
|||
// so we use Backbone.history.navigate instead.
|
||||
var change = Backbone.history.navigate(link.attr("href").substring(1) ,true);
|
||||
if(change === undefined) { Backbone.history.loadUrl(link.attr("href").substring(1)); }
|
||||
app.notificationsCollection.fetch();
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
|||
114
app/assets/javascripts/app/collections/notifications.js
Normal file
114
app/assets/javascripts/app/collections/notifications.js
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
app.collections.Notifications = Backbone.Collection.extend({
|
||||
model: app.models.Notification,
|
||||
// URL parameter
|
||||
/* eslint-disable camelcase */
|
||||
url: Routes.notifications({per_page: 10, page: 1}),
|
||||
/* eslint-enable camelcase */
|
||||
page: 2,
|
||||
perPage: 5,
|
||||
unreadCount: 0,
|
||||
unreadCountByType: {},
|
||||
timeout: 300000, // 5 minutes
|
||||
|
||||
initialize: function() {
|
||||
this.fetch();
|
||||
setInterval(this.pollNotifications.bind(this), this.timeout);
|
||||
Diaspora.BrowserNotification.requestPermission();
|
||||
},
|
||||
|
||||
pollNotifications: function() {
|
||||
var unreadCountBefore = this.unreadCount;
|
||||
this.fetch();
|
||||
|
||||
this.once("finishedLoading", function() {
|
||||
if (unreadCountBefore < this.unreadCount) {
|
||||
Diaspora.BrowserNotification.spawnNotification(
|
||||
Diaspora.I18n.t("notifications.new_notifications", {count: this.unreadCount}));
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
fetch: function(options) {
|
||||
options = options || {};
|
||||
options.remove = false;
|
||||
options.merge = true;
|
||||
options.parse = true;
|
||||
Backbone.Collection.prototype.fetch.apply(this, [options]);
|
||||
},
|
||||
|
||||
fetchMore: function() {
|
||||
var hasMoreNotifications = (this.page * this.perPage) <= this.length;
|
||||
// There are more notifications to load on the current page
|
||||
if (hasMoreNotifications) {
|
||||
this.page++;
|
||||
// URL parameter
|
||||
/* eslint-disable camelcase */
|
||||
var route = Routes.notifications({per_page: this.perPage, page: this.page});
|
||||
/* eslint-enable camelcase */
|
||||
this.fetch({url: route, pushBack: true});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds new models to the collection at the end or at the beginning of the collection and
|
||||
* then fires an event for each model of the collection. It will fire a different event
|
||||
* based on whether the models were added at the end (typically when the scroll triggers to load more
|
||||
* notifications) or at the beginning (new notifications have been added to the front of the list).
|
||||
*/
|
||||
set: function(items, options) {
|
||||
options = options || {};
|
||||
options.at = options.pushBack ? this.length : 0;
|
||||
|
||||
// Retreive back the new created models
|
||||
var models = [];
|
||||
var accu = function(model) { models.push(model); };
|
||||
this.on("add", accu);
|
||||
Backbone.Collection.prototype.set.apply(this, [items, options]);
|
||||
this.off("add", accu);
|
||||
|
||||
if (options.pushBack) {
|
||||
models.forEach(function(model) { this.trigger("pushBack", model); }.bind(this));
|
||||
} else {
|
||||
// Fires events in the reverse order so that the first event is prepended in first position
|
||||
models.reverse();
|
||||
models.forEach(function(model) { this.trigger("pushFront", model); }.bind(this));
|
||||
}
|
||||
this.trigger("finishedLoading");
|
||||
},
|
||||
|
||||
parse: function(response) {
|
||||
this.unreadCount = response.unread_count;
|
||||
this.unreadCountByType = response.unread_count_by_type;
|
||||
|
||||
return _.map(response.notification_list, function(item) {
|
||||
/* eslint-disable new-cap */
|
||||
var model = new this.model(item);
|
||||
/* eslint-enable new-cap */
|
||||
model.on("change:unread", this.onChangedUnreadStatus.bind(this));
|
||||
return model;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
setAllRead: function() {
|
||||
this.forEach(function(model) { model.setRead(); });
|
||||
},
|
||||
|
||||
setRead: function(guid) {
|
||||
this.find(function(model) { return model.guid === guid; }).setRead();
|
||||
},
|
||||
|
||||
setUnread: function(guid) {
|
||||
this.find(function(model) { return model.guid === guid; }).setUnread();
|
||||
},
|
||||
|
||||
onChangedUnreadStatus: function(model) {
|
||||
if (model.get("unread") === true) {
|
||||
this.unreadCount++;
|
||||
this.unreadCountByType[model.get("type")]++;
|
||||
} else {
|
||||
this.unreadCount = Math.max(this.unreadCount - 1, 0);
|
||||
this.unreadCountByType[model.get("type")] = Math.max(this.unreadCountByType[model.get("type")] - 1, 0);
|
||||
}
|
||||
this.trigger("update");
|
||||
}
|
||||
});
|
||||
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
app.collections.Reshares = Backbone.Collection.extend({
|
||||
model: app.models.Reshare,
|
||||
url : "/reshares"
|
||||
|
||||
initialize: function(models, options) {
|
||||
this.url = "/posts/" + options.post.id + "/reshares";
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
69
app/assets/javascripts/app/models/notification.js
Normal file
69
app/assets/javascripts/app/models/notification.js
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
app.models.Notification = Backbone.Model.extend({
|
||||
constructor: function(attributes, options) {
|
||||
options = options || {};
|
||||
options.parse = true;
|
||||
Backbone.Model.apply(this, [attributes, options]);
|
||||
this.guid = this.get("id");
|
||||
},
|
||||
|
||||
/**
|
||||
* Flattens the notification object returned by the server.
|
||||
*
|
||||
* The server returns an object that looks like:
|
||||
*
|
||||
* {
|
||||
* "reshared": {
|
||||
* "id": 45,
|
||||
* "target_type": "Post",
|
||||
* "target_id": 11,
|
||||
* "recipient_id": 1,
|
||||
* "unread": true,
|
||||
* "created_at": "2015-10-27T19:56:30.000Z",
|
||||
* "updated_at": "2015-10-27T19:56:30.000Z",
|
||||
* "note_html": <html/>
|
||||
* },
|
||||
* "type": "reshared"
|
||||
* }
|
||||
*
|
||||
* The returned object looks like:
|
||||
*
|
||||
* {
|
||||
* "type": "reshared",
|
||||
* "id": 45,
|
||||
* "target_type": "Post",
|
||||
* "target_id": 11,
|
||||
* "recipient_id": 1,
|
||||
* "unread": true,
|
||||
* "created_at": "2015-10-27T19:56:30.000Z",
|
||||
* "updated_at": "2015-10-27T19:56:30.000Z",
|
||||
* "note_html": <html/>,
|
||||
* }
|
||||
*/
|
||||
parse: function(response) {
|
||||
var result = {type: response.type};
|
||||
result = $.extend(result, response[result.type]);
|
||||
return result;
|
||||
},
|
||||
|
||||
setRead: function() {
|
||||
this.setUnreadStatus(false);
|
||||
},
|
||||
|
||||
setUnread: function() {
|
||||
this.setUnreadStatus(true);
|
||||
},
|
||||
|
||||
setUnreadStatus: function(state) {
|
||||
if (this.get("unread") !== state) {
|
||||
$.ajax({
|
||||
url: Routes.notification(this.guid),
|
||||
/* eslint-disable camelcase */
|
||||
data: {set_unread: state},
|
||||
/* eslint-enable camelcase */
|
||||
type: "PUT",
|
||||
context: this,
|
||||
success: function() { this.set("unread", state); }
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -70,9 +70,10 @@ app.models.Post.Interactions = Backbone.Model.extend({
|
|||
self.post.set({participation: true});
|
||||
self.trigger("change");
|
||||
self.set({"likes_count" : self.get("likes_count") + 1});
|
||||
self.likes.trigger("change");
|
||||
},
|
||||
error: function() {
|
||||
app.flashMessages.error(Diaspora.I18n.t("failed_to_like"));
|
||||
error: function(model, response) {
|
||||
app.flashMessages.handleAjaxError(response);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -84,23 +85,26 @@ app.models.Post.Interactions = Backbone.Model.extend({
|
|||
this.userLike().destroy({success : function() {
|
||||
self.trigger('change');
|
||||
self.set({"likes_count" : self.get("likes_count") - 1});
|
||||
self.likes.trigger("change");
|
||||
}});
|
||||
|
||||
app.instrument("track", "Unlike");
|
||||
},
|
||||
|
||||
comment : function (text) {
|
||||
comment: function(text, options) {
|
||||
var self = this;
|
||||
options = options || {};
|
||||
|
||||
this.comments.make(text).fail(function () {
|
||||
app.flashMessages.error(Diaspora.I18n.t("failed_to_comment"));
|
||||
this.comments.make(text).fail(function(response) {
|
||||
app.flashMessages.handleAjaxError(response);
|
||||
if (options.error) { options.error(); }
|
||||
}).done(function() {
|
||||
self.post.set({participation: true});
|
||||
self.set({"comments_count": self.get("comments_count") + 1});
|
||||
self.trigger('change'); //updates after sync
|
||||
if (options.success) { options.success(); }
|
||||
});
|
||||
|
||||
this.trigger("change"); //updates count in an eager manner
|
||||
|
||||
app.instrument("track", "Comment");
|
||||
},
|
||||
|
||||
|
|
@ -116,9 +120,11 @@ app.models.Post.Interactions = Backbone.Model.extend({
|
|||
app.stream.addNow(reshare);
|
||||
}
|
||||
interactions.trigger("change");
|
||||
interactions.set({"reshares_count": interactions.get("reshares_count") + 1});
|
||||
interactions.reshares.trigger("change");
|
||||
})
|
||||
.fail(function(){
|
||||
app.flashMessages.error(Diaspora.I18n.t("reshares.duplicate"));
|
||||
.fail(function(response) {
|
||||
app.flashMessages.handleAjaxError(response);
|
||||
});
|
||||
|
||||
app.instrument("track", "Reshare");
|
||||
|
|
|
|||
|
|
@ -79,6 +79,9 @@ app.pages.Contacts = Backbone.View.extend({
|
|||
},
|
||||
|
||||
showMessageModal: function(){
|
||||
$("#conversationModal").on("modal:loaded", function() {
|
||||
new app.views.ConversationsForm({prefill: gon.conversationPrefill});
|
||||
});
|
||||
app.helpers.showModal("#conversationModal");
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ app.pages.Profile = app.views.Base.extend({
|
|||
this.streamCollection = _.has(opts, "streamCollection") ? opts.streamCollection : null;
|
||||
this.streamViewClass = _.has(opts, "streamView") ? opts.streamView : null;
|
||||
|
||||
this.model.on("change", this.render, this);
|
||||
this.model.on("sync", this._done, this);
|
||||
|
||||
// bind to global events
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ app.Router = Backbone.Router.extend({
|
|||
notifications: function() {
|
||||
this._loadContacts();
|
||||
this.renderAspectMembershipDropdowns($(document));
|
||||
new app.views.Notifications({el: "#notifications_container"});
|
||||
new app.views.Notifications({el: "#notifications_container", collection: app.notificationsCollection});
|
||||
},
|
||||
|
||||
peopleSearch: function() {
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ app.views.AspectMembership = app.views.Base.extend({
|
|||
_displayError: function(model, resp) {
|
||||
this._done();
|
||||
this.dropdown.closest(".aspect_membership_dropdown").removeClass("open"); // close the dropdown
|
||||
app.flashMessages.error(resp.responseText);
|
||||
app.flashMessages.handleAjaxError(resp);
|
||||
},
|
||||
|
||||
// remove the membership with the given id
|
||||
|
|
@ -134,7 +134,7 @@ app.views.AspectMembership = app.views.Base.extend({
|
|||
this.listenToOnce(membership, "sync", this._successDestroyCb);
|
||||
this.listenToOnce(membership, "error", this._displayError);
|
||||
|
||||
return membership.destroy();
|
||||
return membership.destroy({wait: true});
|
||||
},
|
||||
|
||||
_successDestroyCb: function(aspectMembership) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ app.views.CommentStream = app.views.Base.extend({
|
|||
|
||||
postRenderTemplate : function() {
|
||||
this.model.comments.each(this.appendComment, this);
|
||||
this.commentBox = this.$(".comment_box");
|
||||
this.commentSubmitButton = this.$("input[name='commit']");
|
||||
},
|
||||
|
||||
presenter: function(){
|
||||
|
|
@ -38,15 +40,35 @@ app.views.CommentStream = app.views.Base.extend({
|
|||
createComment: function(evt) {
|
||||
if(evt){ evt.preventDefault(); }
|
||||
|
||||
var commentText = $.trim(this.$('.comment_box').val());
|
||||
this.$(".comment_box").val("");
|
||||
this.$(".comment_box").css("height", "");
|
||||
if(commentText) {
|
||||
this.model.comment(commentText);
|
||||
return this;
|
||||
} else {
|
||||
this.$(".comment_box").focus();
|
||||
var commentText = $.trim(this.commentBox.val());
|
||||
if (commentText === "") {
|
||||
this.commentBox.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
this.disableCommentBox();
|
||||
|
||||
this.model.comment(commentText, {
|
||||
success: function() {
|
||||
this.commentBox.val("");
|
||||
this.enableCommentBox();
|
||||
autosize.update(this.commentBox);
|
||||
}.bind(this),
|
||||
error: function() {
|
||||
this.enableCommentBox();
|
||||
this.commentBox.focus();
|
||||
}.bind(this)
|
||||
});
|
||||
},
|
||||
|
||||
disableCommentBox: function() {
|
||||
this.commentBox.prop("disabled", true);
|
||||
this.commentSubmitButton.prop("disabled", true);
|
||||
},
|
||||
|
||||
enableCommentBox: function() {
|
||||
this.commentBox.removeAttr("disabled");
|
||||
this.commentSubmitButton.removeAttr("disabled");
|
||||
},
|
||||
|
||||
keyDownOnCommentBox: function(evt) {
|
||||
|
|
@ -104,10 +126,12 @@ app.views.CommentStream = app.views.Base.extend({
|
|||
},
|
||||
|
||||
expandComments: function(evt){
|
||||
this.$(".loading-comments").removeClass("hidden");
|
||||
if(evt){ evt.preventDefault(); }
|
||||
this.model.comments.fetch({
|
||||
success: function() {
|
||||
this.$("div.comment.show_comments").addClass("hidden");
|
||||
this.$(".loading-comments").addClass("hidden");
|
||||
}.bind(this)
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,40 +5,83 @@ app.views.ConversationsForm = Backbone.View.extend({
|
|||
|
||||
events: {
|
||||
"keydown .conversation-message-text": "keyDown",
|
||||
"click .conversation-recipient-tag .remove": "removeRecipient"
|
||||
},
|
||||
|
||||
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}];
|
||||
opts = opts || {};
|
||||
this.conversationRecipients = [];
|
||||
|
||||
this.typeaheadElement = this.$el.find("#contacts-search-input");
|
||||
this.contactsIdsListInput = this.$el.find("#contact-ids");
|
||||
this.tagListElement = this.$("#recipients-tag-list");
|
||||
|
||||
this.search = new app.views.SearchBase({
|
||||
el: this.$el.find("#new-conversation"),
|
||||
typeaheadInput: this.typeaheadElement,
|
||||
customSearch: true,
|
||||
autoselect: true,
|
||||
remoteRoute: {url: "/contacts", extraParameters: "mutual=true"}
|
||||
});
|
||||
|
||||
this.bindTypeaheadEvents();
|
||||
|
||||
this.tagListElement.empty();
|
||||
if (opts.prefill) {
|
||||
this.prefill(opts.prefill);
|
||||
}
|
||||
this.prepareAutocomplete(this.contacts);
|
||||
|
||||
this.$("form#new-conversation").on("ajax:success", this.conversationCreateSuccess);
|
||||
this.$("form#new-conversation").on("ajax:error", this.conversationCreateError);
|
||||
},
|
||||
|
||||
prepareAutocomplete: function(data){
|
||||
this.$("#contact-autocomplete").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
|
||||
});
|
||||
$("#contact_ids").attr("aria-labelledby", "toLabel").focus();
|
||||
addRecipient: function(person) {
|
||||
this.conversationRecipients.push(person);
|
||||
this.updateContactIdsListInput();
|
||||
/* eslint-disable camelcase */
|
||||
this.tagListElement.append(HandlebarsTemplates.conversation_recipient_tag_tpl(person));
|
||||
/* eslint-enable camelcase */
|
||||
},
|
||||
|
||||
keyDown : function(evt) {
|
||||
if(evt.which === Keycodes.ENTER && evt.ctrlKey) {
|
||||
prefill: function(handles) {
|
||||
handles.forEach(this.addRecipient.bind(this));
|
||||
},
|
||||
|
||||
updateContactIdsListInput: function() {
|
||||
this.contactsIdsListInput.val(_(this.conversationRecipients).pluck("id").join(","));
|
||||
this.search.ignoreDiasporaIds.length = 0;
|
||||
this.conversationRecipients.forEach(this.search.ignorePersonForSuggestions.bind(this.search));
|
||||
},
|
||||
|
||||
bindTypeaheadEvents: function() {
|
||||
this.typeaheadElement.on("typeahead:select", function(evt, person) {
|
||||
this.onSuggestionSelection(person);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
onSuggestionSelection: function(person) {
|
||||
this.addRecipient(person);
|
||||
this.typeaheadElement.typeahead("val", "");
|
||||
},
|
||||
|
||||
keyDown: function(evt) {
|
||||
if (evt.which === Keycodes.ENTER && evt.ctrlKey) {
|
||||
$(evt.target).parents("form").submit();
|
||||
}
|
||||
},
|
||||
|
||||
removeRecipient: function(evt) {
|
||||
var $recipientTagEl = $(evt.target).parents(".conversation-recipient-tag");
|
||||
var diasporaHandle = $recipientTagEl.data("diaspora-handle");
|
||||
|
||||
this.conversationRecipients = this.conversationRecipients.filter(function(person) {
|
||||
return diasporaHandle !== person.handle;
|
||||
});
|
||||
|
||||
this.updateContactIdsListInput();
|
||||
$recipientTagEl.remove();
|
||||
},
|
||||
|
||||
conversationCreateSuccess: function(evt, data) {
|
||||
app._changeLocation(Routes.conversation(data.id));
|
||||
},
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ app.views.ConversationsInbox = Backbone.View.extend({
|
|||
},
|
||||
|
||||
initialize: function() {
|
||||
new app.views.ConversationsForm({contacts: gon.contacts});
|
||||
new app.views.ConversationsForm();
|
||||
this.setupConversation();
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -16,5 +16,13 @@ app.views.FlashMessages = app.views.Base.extend({
|
|||
|
||||
error: function(message){
|
||||
this._flash(message, true);
|
||||
},
|
||||
|
||||
handleAjaxError: function(response) {
|
||||
if (response.status === 0) {
|
||||
this.error(Diaspora.I18n.t("errors.connection"));
|
||||
} else {
|
||||
this.error(response.responseText);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@ app.views.Header = app.views.Base.extend({
|
|||
});
|
||||
},
|
||||
|
||||
postRenderTemplate: function(){
|
||||
new app.views.Notifications({ el: "#notification-dropdown" });
|
||||
this.notificationDropdown = new app.views.NotificationDropdown({ el: "#notification-dropdown" });
|
||||
new app.views.Search({ el: "#header-search-form" });
|
||||
postRenderTemplate: function() {
|
||||
new app.views.Notifications({el: "#notification-dropdown", collection: app.notificationsCollection});
|
||||
new app.views.NotificationDropdown({el: "#notification-dropdown", collection: app.notificationsCollection});
|
||||
new app.views.Search({el: "#header-search-form"});
|
||||
},
|
||||
|
||||
menuElement: function(){ return this.$("ul.dropdown"); },
|
||||
menuElement: function() { return this.$("ul.dropdown"); }
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ app.views.LikesInfo = app.views.Base.extend({
|
|||
tooltipSelector : ".avatar",
|
||||
|
||||
initialize : function() {
|
||||
this.model.interactions.bind('change', this.render, this);
|
||||
this.model.interactions.likes.on("change", this.render, this);
|
||||
this.displayAvatars = false;
|
||||
},
|
||||
|
||||
|
|
@ -19,18 +19,16 @@ app.views.LikesInfo = app.views.Base.extend({
|
|||
return _.extend(this.defaultPresenter(), {
|
||||
likes : this.model.interactions.likes.toJSON(),
|
||||
likesCount : this.model.interactions.likesCount(),
|
||||
displayAvatars : this.model.interactions.get("fetched") && this.displayAvatars
|
||||
displayAvatars: this.displayAvatars
|
||||
});
|
||||
},
|
||||
|
||||
showAvatars : function(evt){
|
||||
if(evt) { evt.preventDefault() }
|
||||
this.displayAvatars = true;
|
||||
if(!this.model.interactions.get("fetched")){
|
||||
this.model.interactions.fetch();
|
||||
} else {
|
||||
this.model.interactions.trigger("change");
|
||||
}
|
||||
this.model.interactions.likes.fetch({success: function() {
|
||||
this.model.interactions.likes.trigger("change");
|
||||
}.bind(this)});
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -6,16 +6,21 @@ app.views.NotificationDropdown = app.views.Base.extend({
|
|||
},
|
||||
|
||||
initialize: function(){
|
||||
$(document.body).click($.proxy(this.hideDropdown, this));
|
||||
$(document.body).click(this.hideDropdown.bind(this));
|
||||
|
||||
this.notifications = [];
|
||||
this.perPage = 5;
|
||||
this.hasMoreNotifs = true;
|
||||
this.badge = this.$el;
|
||||
this.dropdown = $("#notification-dropdown");
|
||||
this.dropdownNotifications = this.dropdown.find(".notifications");
|
||||
this.ajaxLoader = this.dropdown.find(".ajax-loader");
|
||||
this.perfectScrollbarInitialized = false;
|
||||
this.dropdownNotifications.scroll(this.dropdownScroll.bind(this));
|
||||
this.bindCollectionEvents();
|
||||
},
|
||||
|
||||
bindCollectionEvents: function() {
|
||||
this.collection.on("pushFront", this.onPushFront.bind(this));
|
||||
this.collection.on("pushBack", this.onPushBack.bind(this));
|
||||
this.collection.on("finishedLoading", this.finishLoading.bind(this));
|
||||
},
|
||||
|
||||
toggleDropdown: function(evt){
|
||||
|
|
@ -31,12 +36,11 @@ app.views.NotificationDropdown = app.views.Base.extend({
|
|||
},
|
||||
|
||||
showDropdown: function(){
|
||||
this.resetParams();
|
||||
this.ajaxLoader.show();
|
||||
this.dropdown.addClass("dropdown-open");
|
||||
this.updateScrollbar();
|
||||
this.dropdownNotifications.addClass("loading");
|
||||
this.getNotifications();
|
||||
this.collection.fetch();
|
||||
},
|
||||
|
||||
hideDropdown: function(evt){
|
||||
|
|
@ -50,40 +54,18 @@ app.views.NotificationDropdown = app.views.Base.extend({
|
|||
|
||||
dropdownScroll: function(){
|
||||
var isLoading = ($(".loading").length === 1);
|
||||
if (this.isBottom() && this.hasMoreNotifs && !isLoading){
|
||||
if (this.isBottom() && !isLoading) {
|
||||
this.dropdownNotifications.addClass("loading");
|
||||
this.getNotifications();
|
||||
this.collection.fetchMore();
|
||||
}
|
||||
},
|
||||
|
||||
getParams: function(){
|
||||
if(this.notifications.length === 0){ return{ per_page: 10, page: 1 }; }
|
||||
else{ return{ per_page: this.perPage, page: this.nextPage }; }
|
||||
},
|
||||
|
||||
resetParams: function(){
|
||||
this.notifications.length = 0;
|
||||
this.hasMoreNotifs = true;
|
||||
delete this.nextPage;
|
||||
},
|
||||
|
||||
isBottom: function(){
|
||||
var bottom = this.dropdownNotifications.prop("scrollHeight") - this.dropdownNotifications.height();
|
||||
var currentPosition = this.dropdownNotifications.scrollTop();
|
||||
return currentPosition + 50 >= bottom;
|
||||
},
|
||||
|
||||
getNotifications: function(){
|
||||
var self = this;
|
||||
$.getJSON(Routes.notifications(this.getParams()), function(notifications){
|
||||
$.each(notifications, function(){ self.notifications.push(this); });
|
||||
self.hasMoreNotifs = notifications.length >= self.perPage;
|
||||
if(self.nextPage){ self.nextPage++; }
|
||||
else { self.nextPage = 3; }
|
||||
self.renderNotifications();
|
||||
});
|
||||
},
|
||||
|
||||
hideAjaxLoader: function(){
|
||||
var self = this;
|
||||
this.ajaxLoader.find(".spinner").fadeTo(200, 0, function(){
|
||||
|
|
@ -93,28 +75,23 @@ app.views.NotificationDropdown = app.views.Base.extend({
|
|||
});
|
||||
},
|
||||
|
||||
renderNotifications: function(){
|
||||
var self = this;
|
||||
this.dropdownNotifications.find(".media.stream-element").remove();
|
||||
$.each(self.notifications, function(index, notifications){
|
||||
$.each(notifications, function(index, notification){
|
||||
if($.inArray(notification, notifications) === -1){
|
||||
var node = self.dropdownNotifications.append(notification.note_html);
|
||||
$(node).find(".unread-toggle .entypo-eye").tooltip("destroy").tooltip();
|
||||
$(node).find(self.avatars.selector).error(self.avatars.fallback);
|
||||
}
|
||||
});
|
||||
});
|
||||
onPushBack: function(notification) {
|
||||
var node = this.dropdownNotifications.append(notification.get("note_html"));
|
||||
$(node).find(".unread-toggle .entypo-eye").tooltip("destroy").tooltip();
|
||||
$(node).find(this.avatars.selector).error(this.avatars.fallback);
|
||||
},
|
||||
|
||||
this.hideAjaxLoader();
|
||||
onPushFront: function(notification) {
|
||||
var node = this.dropdownNotifications.prepend(notification.get("note_html"));
|
||||
$(node).find(".unread-toggle .entypo-eye").tooltip("destroy").tooltip();
|
||||
$(node).find(this.avatars.selector).error(this.avatars.fallback);
|
||||
},
|
||||
|
||||
finishLoading: function() {
|
||||
app.helpers.timeago(this.dropdownNotifications);
|
||||
|
||||
this.updateScrollbar();
|
||||
this.hideAjaxLoader();
|
||||
this.dropdownNotifications.removeClass("loading");
|
||||
this.dropdownNotifications.scroll(function(){
|
||||
self.dropdownScroll();
|
||||
});
|
||||
},
|
||||
|
||||
updateScrollbar: function() {
|
||||
|
|
|
|||
|
|
@ -1,96 +1,85 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Notifications = Backbone.View.extend({
|
||||
|
||||
events: {
|
||||
"click .unread-toggle" : "toggleUnread",
|
||||
"click #mark_all_read_link": "markAllRead"
|
||||
"click .unread-toggle": "toggleUnread",
|
||||
"click #mark-all-read-link": "markAllRead"
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
$(".unread-toggle .entypo-eye").tooltip();
|
||||
app.helpers.timeago($(document));
|
||||
this.bindCollectionEvents();
|
||||
},
|
||||
|
||||
bindCollectionEvents: function() {
|
||||
this.collection.on("change", this.onChangedUnreadStatus.bind(this));
|
||||
this.collection.on("update", this.updateView.bind(this));
|
||||
},
|
||||
|
||||
toggleUnread: function(evt) {
|
||||
var note = $(evt.target).closest(".stream-element");
|
||||
var unread = note.hasClass("unread");
|
||||
var guid = note.data("guid");
|
||||
if (unread){ this.setRead(guid); }
|
||||
else { this.setUnread(guid); }
|
||||
},
|
||||
|
||||
getAllUnread: function() { return $(".media.stream-element.unread"); },
|
||||
|
||||
setRead: function(guid) { this.setUnreadStatus(guid, false); },
|
||||
|
||||
setUnread: function(guid){ this.setUnreadStatus(guid, true); },
|
||||
|
||||
setUnreadStatus: function(guid, state){
|
||||
$.ajax({
|
||||
url: "/notifications/" + guid,
|
||||
data: { set_unread: state },
|
||||
type: "PUT",
|
||||
context: this,
|
||||
success: this.clickSuccess
|
||||
});
|
||||
},
|
||||
|
||||
clickSuccess: function(data) {
|
||||
var guid = data.guid;
|
||||
var type = $(".stream-element[data-guid=" + guid + "]").data("type");
|
||||
this.updateView(guid, type, data.unread);
|
||||
},
|
||||
|
||||
markAllRead: function(evt){
|
||||
if(evt) { evt.preventDefault(); }
|
||||
var self = this;
|
||||
this.getAllUnread().each(function(i, el){
|
||||
self.setRead($(el).data("guid"));
|
||||
});
|
||||
},
|
||||
|
||||
updateView: function(guid, type, unread) {
|
||||
var change = unread ? 1 : -1,
|
||||
allNotes = $("#notifications_container .list-group > a:eq(0) .badge"),
|
||||
typeNotes = $("#notifications_container .list-group > a[data-type=" + type + "] .badge"),
|
||||
headerBadge = $(".notifications-link .badge"),
|
||||
note = $(".notifications .stream-element[data-guid=" + guid + "]"),
|
||||
markAllReadLink = $("a#mark_all_read_link"),
|
||||
translationKey = unread ? "notifications.mark_read" : "notifications.mark_unread";
|
||||
|
||||
if(unread){ note.removeClass("read").addClass("unread"); }
|
||||
else { note.removeClass("unread").addClass("read"); }
|
||||
|
||||
$(".unread-toggle .entypo-eye", note)
|
||||
.tooltip("destroy")
|
||||
.removeAttr("data-original-title")
|
||||
.attr("title",Diaspora.I18n.t(translationKey))
|
||||
.tooltip();
|
||||
|
||||
[allNotes, typeNotes, headerBadge].forEach(function(element){
|
||||
element.text(function(i, text){
|
||||
return parseInt(text) + change;
|
||||
});
|
||||
});
|
||||
|
||||
[allNotes, typeNotes].forEach(function(badge) {
|
||||
if(badge.text() > 0) {
|
||||
badge.removeClass("hidden");
|
||||
}
|
||||
else {
|
||||
badge.addClass("hidden");
|
||||
}
|
||||
});
|
||||
|
||||
if(headerBadge.text() > 0){
|
||||
headerBadge.removeClass("hidden");
|
||||
markAllReadLink.removeClass("disabled");
|
||||
if (unread) {
|
||||
this.collection.setRead(guid);
|
||||
} else {
|
||||
this.collection.setUnread(guid);
|
||||
}
|
||||
else{
|
||||
headerBadge.addClass("hidden");
|
||||
},
|
||||
|
||||
markAllRead: function() {
|
||||
this.collection.setAllRead();
|
||||
},
|
||||
|
||||
onChangedUnreadStatus: function(model) {
|
||||
var unread = model.get("unread");
|
||||
var translationKey = unread ? "notifications.mark_read" : "notifications.mark_unread";
|
||||
var note = $(".stream-element[data-guid=" + model.guid + "]");
|
||||
|
||||
note.find(".entypo-eye")
|
||||
.tooltip("destroy")
|
||||
.removeAttr("data-original-title")
|
||||
.attr("title", Diaspora.I18n.t(translationKey))
|
||||
.tooltip();
|
||||
|
||||
if (unread) {
|
||||
note.removeClass("read").addClass("unread");
|
||||
} else {
|
||||
note.removeClass("unread").addClass("read");
|
||||
}
|
||||
},
|
||||
|
||||
updateView: function() {
|
||||
var notificationsContainer = $("#notifications_container");
|
||||
|
||||
// update notification counts in the sidebar
|
||||
Object.keys(this.collection.unreadCountByType).forEach(function(notificationType) {
|
||||
var count = this.collection.unreadCountByType[notificationType];
|
||||
this.updateBadge(notificationsContainer.find("a[data-type=" + notificationType + "] .badge"), count);
|
||||
}.bind(this));
|
||||
|
||||
this.updateBadge(notificationsContainer.find("a[data-type=all] .badge"), this.collection.unreadCount);
|
||||
|
||||
// update notification count in the header
|
||||
this.updateBadge($(".notifications-link .badge"), this.collection.unreadCount);
|
||||
|
||||
var markAllReadLink = $("a#mark-all-read-link");
|
||||
|
||||
if (this.collection.unreadCount > 0) {
|
||||
markAllReadLink.removeClass("disabled");
|
||||
} else {
|
||||
markAllReadLink.addClass("disabled");
|
||||
}
|
||||
},
|
||||
|
||||
updateBadge: function(badge, count) {
|
||||
badge.text(count);
|
||||
if (count > 0) {
|
||||
badge.removeClass("hidden");
|
||||
} else {
|
||||
badge.addClass("hidden");
|
||||
}
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ app.views.ProfileHeader = app.views.Base.extend({
|
|||
initialize: function(opts) {
|
||||
this.photos = _.has(opts, 'photos') ? opts.photos : null;
|
||||
this.contacts = _.has(opts, 'contacts') ? opts.contacts : null;
|
||||
this.model.on("change", this.render, this);
|
||||
$("#mentionModal").on("modal:loaded", this.mentionModalLoaded.bind(this));
|
||||
$("#mentionModal").on("hidden.bs.modal", this.mentionModalHidden);
|
||||
},
|
||||
|
|
@ -79,8 +80,11 @@ app.views.ProfileHeader = app.views.Base.extend({
|
|||
},
|
||||
|
||||
showMessageModal: function(){
|
||||
$("#conversationModal").on("modal:loaded", function() {
|
||||
new app.views.ConversationsForm({prefill: gon.conversationPrefill});
|
||||
});
|
||||
app.helpers.showModal("#conversationModal");
|
||||
},
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ app.views.PublisherMention = app.views.SearchBase.extend({
|
|||
typeaheadInput: this.typeaheadInput,
|
||||
customSearch: true,
|
||||
autoselect: true,
|
||||
remoteRoute: "/contacts"
|
||||
remoteRoute: {url: "/contacts"}
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ app.views.ResharesInfo = app.views.Base.extend({
|
|||
tooltipSelector : ".avatar",
|
||||
|
||||
initialize : function() {
|
||||
this.model.interactions.bind("change", this.render, this);
|
||||
this.model.interactions.reshares.bind("change", this.render, this);
|
||||
this.displayAvatars = false;
|
||||
},
|
||||
|
||||
|
|
@ -19,18 +19,16 @@ app.views.ResharesInfo = app.views.Base.extend({
|
|||
return _.extend(this.defaultPresenter(), {
|
||||
reshares : this.model.interactions.reshares.toJSON(),
|
||||
resharesCount : this.model.interactions.resharesCount(),
|
||||
displayAvatars : this.model.interactions.get("fetched") && this.displayAvatars
|
||||
displayAvatars: this.displayAvatars
|
||||
});
|
||||
},
|
||||
|
||||
showAvatars : function(evt){
|
||||
if(evt) { evt.preventDefault() }
|
||||
this.displayAvatars = true;
|
||||
if(!this.model.interactions.get("fetched")){
|
||||
this.model.interactions.fetch();
|
||||
} else {
|
||||
this.model.interactions.trigger("change");
|
||||
}
|
||||
this.model.interactions.reshares.fetch({success: function() {
|
||||
this.model.interactions.reshares.trigger("change");
|
||||
}.bind(this)});
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -28,9 +28,13 @@ app.views.SearchBase = app.views.Base.extend({
|
|||
};
|
||||
|
||||
// Allow bloodhound to look for remote results if there is a route given in the options
|
||||
if(options.remoteRoute) {
|
||||
if (options.remoteRoute && options.remoteRoute.url) {
|
||||
var extraParameters = "";
|
||||
if (options.remoteRoute.extraParameters) {
|
||||
extraParameters += "&" + options.remoteRoute.extraParameters;
|
||||
}
|
||||
bloodhoundOptions.remote = {
|
||||
url: options.remoteRoute + ".json?q=%QUERY",
|
||||
url: options.remoteRoute.url + ".json?q=%QUERY" + extraParameters,
|
||||
wildcard: "%QUERY",
|
||||
transform: this.transformBloodhoundResponse.bind(this)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ app.views.Search = app.views.SearchBase.extend({
|
|||
this.searchInput = this.$("#q");
|
||||
app.views.SearchBase.prototype.initialize.call(this, {
|
||||
typeaheadInput: this.searchInput,
|
||||
remoteRoute: this.$el.attr("action"),
|
||||
remoteRoute: {url: this.$el.attr("action")},
|
||||
suggestionLink: true
|
||||
});
|
||||
this.searchInput.on("typeahead:select", this.suggestionSelected);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ app.views.Tags = Backbone.View.extend({
|
|||
if(app.publisher) {
|
||||
app.publisher.setText("#"+ opts.hashtagName + " ");
|
||||
}
|
||||
// add avatar fallback if it can't be loaded
|
||||
$(app.views.Base.prototype.avatars.selector).error(app.views.Base.prototype.avatars.fallback);
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
22
app/assets/javascripts/helpers/browser_notification.js
Normal file
22
app/assets/javascripts/helpers/browser_notification.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
Diaspora.BrowserNotification = {
|
||||
requestPermission: function() {
|
||||
if ("Notification" in window && Notification.permission !== "granted" && Notification.permission !== "denied") {
|
||||
Notification.requestPermission();
|
||||
}
|
||||
},
|
||||
|
||||
spawnNotification: function(title, summary) {
|
||||
if ("Notification" in window && Notification.permission === "granted") {
|
||||
if (!_.isString(title)) {
|
||||
throw new Error("No notification title given.");
|
||||
}
|
||||
|
||||
summary = summary || "";
|
||||
|
||||
new Notification(title, {
|
||||
body: summary,
|
||||
icon: ImagePaths.get("branding/logos/asterisk_white_mobile.png")
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -18,7 +18,7 @@ Diaspora.I18n = {
|
|||
},
|
||||
|
||||
updateLocale: function(locale, data) {
|
||||
locale.data = $.extend(locale.data, data);
|
||||
locale.data = $.extend({}, locale.data, data);
|
||||
|
||||
var rule = locale.data.pluralization_rule;
|
||||
if (typeof rule !== "undefined") {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
// initialize jsxc xmpp client
|
||||
$(document).ready(function() {
|
||||
if (app.currentUser.authenticated()) {
|
||||
$.post('api/v1/tokens', null, function(data) {
|
||||
$.post("/user/auth_token", null, function(data) {
|
||||
if (jsxc && data['token']) {
|
||||
var jid = app.currentUser.get('diaspora_id');
|
||||
jsxc.init({
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
//= require markdown-it-sup
|
||||
//= require highlightjs
|
||||
//= require clear-form
|
||||
//= require typeahead.bundle.js
|
||||
//= require corejs-typeahead
|
||||
//= require app/app
|
||||
//= require diaspora
|
||||
//= require_tree ./helpers
|
||||
|
|
|
|||
|
|
@ -98,8 +98,12 @@
|
|||
success: function() {
|
||||
Diaspora.Mobile.PostActions.toggleActive(link);
|
||||
},
|
||||
error: function() {
|
||||
alert(Diaspora.I18n.t("failed_to_reshare"));
|
||||
error: function(response) {
|
||||
if (response.status === 0) {
|
||||
alert(Diaspora.I18n.t("errors.connection"));
|
||||
} else {
|
||||
alert(response.responseText);
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
Diaspora.Mobile.PostActions.hideLoader(link);
|
||||
|
|
|
|||
|
|
@ -187,9 +187,9 @@ $btn-success-color: #333 !default;
|
|||
// $input-bg-disabled: $gray-lighter
|
||||
|
||||
//** Text color for `<input>`s
|
||||
// $input-color: $gray
|
||||
$input-color: $text-dark-grey !default;
|
||||
//** `<input>` border color
|
||||
// $input-border: #ccc
|
||||
$input-border: $border-grey !default;
|
||||
|
||||
// TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
|
||||
//** Default `.form-control` border radius
|
||||
|
|
@ -202,6 +202,7 @@ $btn-success-color: #333 !default;
|
|||
|
||||
//** Border color for inputs on focus
|
||||
// $input-border-focus: #66afe9
|
||||
$input-border-focus: $input-border !default;
|
||||
|
||||
//** Placeholder text color
|
||||
// $input-color-placeholder: #999
|
||||
|
|
@ -668,7 +669,7 @@ $navbar-collapse-max-height: 480px;
|
|||
//
|
||||
//##
|
||||
//** Background color on `.list-group-item`
|
||||
$list-group-bg: $white;
|
||||
$list-group-bg: $white !default;
|
||||
//** `.list-group-item` border color
|
||||
$list-group-border: transparent;
|
||||
//** List group border radius
|
||||
|
|
|
|||
|
|
@ -3,31 +3,32 @@ $black: #000;
|
|||
|
||||
$text-grey: #999;
|
||||
$text-dark-grey: #666;
|
||||
$text: #333;
|
||||
$text-color-pale: $text-grey !default;
|
||||
$text-color-active: $black !default;
|
||||
|
||||
$background-white: $white;
|
||||
$background-grey: #eee;
|
||||
$background-blue: #e7f2f7;
|
||||
$background-grey: #eee !default;
|
||||
$background-blue: #e7f2f7 !default;
|
||||
|
||||
$grey: #2b2b2b;
|
||||
$medium-gray: #ccc;
|
||||
$light-grey: #ddd;
|
||||
|
||||
$border-grey: $light-grey;
|
||||
$border-medium-grey: $medium-gray;
|
||||
$border-dark-grey: $text-grey;
|
||||
$border-medium-grey: #ccc;
|
||||
$border-grey: $light-grey !default;
|
||||
$border-medium-grey: $medium-gray !default;
|
||||
$border-dark-grey: $text-grey !default;
|
||||
|
||||
$link-grey: #777;
|
||||
$link-disabled-grey: $text-grey;
|
||||
|
||||
$green: #8ede3d;
|
||||
$icon-color: $black !default;
|
||||
|
||||
$green: #8ede3d !default;
|
||||
$light-green: lighten($green, 20%);
|
||||
$red: #a80000;
|
||||
$blue: #3f8fba;
|
||||
$red: #a80000 !default;
|
||||
$blue: #3f8fba !default;
|
||||
|
||||
$main-background: #f0f0f0 !default;
|
||||
$sidebars-background: $background-white !default;
|
||||
$left-navbar-drawer-background: darken($sidebars-background, 6%);
|
||||
$main-background: darken($white, 6%) !default;
|
||||
$framed-background: $white !default;
|
||||
$left-navbar-drawer-background: darken($white, 6%) !default;
|
||||
$hovercard-background: $white !default;
|
||||
|
||||
$card-shadow: 0 1px 2px 0 rgba(0, 0, 0, .16), 0 2px 10px 0 rgba(0, 0, 0, .12) !default;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,170 @@
|
|||
// Only overriding existing selectors here, so disable some lint rules
|
||||
// scss-lint:disable IdSelector, SelectorFormat, NestingDepth, SelectorDepth, QualifyingElement
|
||||
body {
|
||||
.navbar.navbar-fixed-top #user_menu .dropdown-menu > li > a {
|
||||
color: $text-color;
|
||||
&:hover { color: $white; }
|
||||
}
|
||||
|
||||
.publisher {
|
||||
.mentions-input-box { background-color: $gray; }
|
||||
form {
|
||||
#publisher_textarea_wrapper { background-color: $gray; }
|
||||
.btn.btn-link.question_mark:hover .entypo-cog { color: $gray-light; }
|
||||
}
|
||||
|
||||
.write-preview-tabs > li.active * { color: $text-color; }
|
||||
.md-preview { background-color: $gray; }
|
||||
.md-cancel:hover .entypo-cross { color: $gray-light; }
|
||||
.publisher-buttonbar .btn.btn-link:hover i { color: $gray-light; }
|
||||
}
|
||||
|
||||
.aspect_dropdown li a .text { color: $dropdown-link-color; }
|
||||
|
||||
.info .tag { background-color: $gray-light; }
|
||||
|
||||
.poll_form .progress {
|
||||
background-color: $gray-dark;
|
||||
.bar { background-color: $gray-light; }
|
||||
}
|
||||
|
||||
.stream-element .collapsible {
|
||||
.markdown-content hr { border-top: 1px solid $hr-border; }
|
||||
.expander {
|
||||
@include linear-gradient(transparent, $gray-light, 0%, 95%);
|
||||
border-bottom: 2px solid $gray-light;
|
||||
color: $text-color;
|
||||
text-shadow: 0 0 7px $black;
|
||||
}
|
||||
}
|
||||
|
||||
code,
|
||||
pre {
|
||||
background-color: $gray-dark;
|
||||
border: 1px solid $border-medium-grey;
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
pre code { border: 0; }
|
||||
|
||||
@import 'highlightjs/darcula';
|
||||
|
||||
#single-post-content .head {
|
||||
#post-info .author { color: lighten($gray-lighter, 27%); }
|
||||
#single-post-actions i.entypo-heart.red:hover { color: $red; }
|
||||
}
|
||||
|
||||
.opengraph a { color: lighten($gray-lighter, 27%); }
|
||||
|
||||
.tag:hover { background-color: desaturate(darken($blue, 35%), 20%); }
|
||||
|
||||
#profile_container .profile_header {
|
||||
#author_info #sharing_message.entypo-check { color: lighten($green, 10%); }
|
||||
}
|
||||
|
||||
#invitationsModal #email_invitation { border-top: 1px dashed $gray-light; }
|
||||
|
||||
#contacts_container #people_stream.contacts .stream-element.in_aspect {
|
||||
background-color: $state-success-bg;
|
||||
border-left: 3px solid darken($state-success-bg, 10%);
|
||||
}
|
||||
|
||||
.left-navbar #tags_list {
|
||||
.as-list {
|
||||
color: $text-color;
|
||||
|
||||
em {
|
||||
background-color: lighten($background-blue, 10%);
|
||||
color: $text-color;
|
||||
}
|
||||
}
|
||||
|
||||
.as-result-item.active { color: $text-color; }
|
||||
}
|
||||
|
||||
#faq .question {
|
||||
background-color: $gray-dark;
|
||||
a.toggle { color: $gray-lighter; }
|
||||
&.collapsed { border: 2px solid $gray-dark; }
|
||||
&.opened {
|
||||
border: 2px solid darken($green, 10%);
|
||||
h4 { background-color: darken($green, 10%); }
|
||||
}
|
||||
|
||||
.answer { background-color: $gray; }
|
||||
}
|
||||
|
||||
#welcome-to-diaspora { background: $orange; }
|
||||
|
||||
.block-form fieldset .form-control:focus { border-color: $input-border; }
|
||||
|
||||
&.page-registrations.action-new,
|
||||
&.page-registrations.action-create {
|
||||
.ball { filter: invert(100%); }
|
||||
}
|
||||
|
||||
.spinner { border-color: $gray-light transparent $gray-light $gray-light; }
|
||||
|
||||
// AutoSuggest CSS
|
||||
ul.as-selections {
|
||||
background-color: $framed-background;
|
||||
|
||||
li.as-selection-item,
|
||||
li.as-selection-item.blur {
|
||||
background-color: $gray-dark;
|
||||
border: 1px solid $gray-darker;
|
||||
box-shadow: 0 1px 1px $gray-darker;
|
||||
color: $text-color;
|
||||
text-shadow: 0 1px 1px $gray-darker;
|
||||
}
|
||||
|
||||
li.as-selection-item a.as-close,
|
||||
li.as-selection-item.blur a.as-close {
|
||||
color: $text-color;
|
||||
text-shadow: 0 1px 1px $gray-darker;
|
||||
}
|
||||
|
||||
li:hover.as-selection-item {
|
||||
background-color: $light-blue;
|
||||
border-color: $brand-primary;
|
||||
color: $white;
|
||||
a.as-close { color: $gray-light; }
|
||||
}
|
||||
|
||||
li.as-selection-item.selected { border-color: $brand-primary; }
|
||||
li.as-selection-item a:hover.as-close { color: $white; }
|
||||
li.as-selection-item a:active.as-close { color: $gray-lighter; }
|
||||
}
|
||||
|
||||
ul.as-list {
|
||||
background-color: $gray-dark;
|
||||
box-shadow: 0 2px 12px $gray-light;
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
li.as-result-item,
|
||||
li.as-message {
|
||||
border: 1px solid $gray-dark;
|
||||
}
|
||||
|
||||
li.as-result-item.active {
|
||||
background-color: $brand-primary;
|
||||
border-color: $brand-primary;
|
||||
text-shadow: none;
|
||||
|
||||
em { background: darken($brand-primary, 10%); }
|
||||
}
|
||||
// End AutoSuggest CSS
|
||||
|
||||
// Bootstrap Switch CSS
|
||||
.bootstrap-switch {
|
||||
border-color: $border-grey;
|
||||
.bootstrap-switch-label { background: $framed-background; }
|
||||
.bootstrap-switch-handle-on.bootstrap-switch-default,
|
||||
.bootstrap-switch-handle-off.bootstrap-switch-default {
|
||||
background: $gray-dark;
|
||||
color: $text-color;
|
||||
}
|
||||
}
|
||||
// End Bootstrap Switch CSS
|
||||
}
|
||||
|
|
@ -17,10 +17,4 @@ body {
|
|||
.left-navbar {
|
||||
border-right: 1px solid $border-grey;
|
||||
}
|
||||
|
||||
.right-sidebar-fixed-background,
|
||||
.right-sidebar-fixed-background,
|
||||
.rightbar {
|
||||
border-left: 1px solid $sidebars-background;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
153
app/assets/stylesheets/color_themes/dark/_style.scss
Normal file
153
app/assets/stylesheets/color_themes/dark/_style.scss
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
// Main color(s)
|
||||
$white: #fff;
|
||||
$black: #000;
|
||||
|
||||
$gray-base: $black;
|
||||
$gray-darker: lighten($gray-base, 6%);
|
||||
$gray-dark: lighten($gray-base, 9.5%);
|
||||
$gray: lighten($gray-base, 13.5%);
|
||||
$gray-light: lighten($gray-base, 28%);
|
||||
$gray-lighter: lighten($gray-base, 58%);
|
||||
|
||||
$green: #346535;
|
||||
$red: #622;
|
||||
$blue: #4183c4;
|
||||
$yellow: #645a1b;
|
||||
$orange: #664100;
|
||||
|
||||
$light-blue: lighten($blue, 5%);
|
||||
|
||||
$brand-primary: darken($blue, 5%);
|
||||
$brand-success: $green;
|
||||
$brand-info: darken(adjust-hue($brand-primary, -30), 15%);
|
||||
$brand-danger: lighten($red, 10%);
|
||||
|
||||
// Bootstrap Variables
|
||||
//== Scaffolding
|
||||
$body-bg: $gray;
|
||||
$text-color: lighten($gray-lighter, 17%);
|
||||
$link-color: $blue;
|
||||
|
||||
//== Tables
|
||||
$table-bg-accent: $gray-dark;
|
||||
$table-border-color: $gray-light;
|
||||
|
||||
//== Buttons
|
||||
$btn-default-color: $gray-lighter;
|
||||
$btn-default-bg: $gray-light;
|
||||
$btn-default-border: $gray-darker;
|
||||
|
||||
$btn-success-color: $white;
|
||||
|
||||
//== Forms
|
||||
$input-bg: $gray-dark;
|
||||
|
||||
$input-color: $text-color;
|
||||
$input-border: $gray-light;
|
||||
$input-border-focus: $brand-primary;
|
||||
|
||||
$input-color-placeholder: lighten($gray-light, 7%);
|
||||
|
||||
$legend-color: $text-color;
|
||||
$legend-border-color: $gray-light;
|
||||
|
||||
//== Dropdowns
|
||||
$dropdown-bg: lighten($gray-base, 15%);
|
||||
$dropdown-divider-bg: $gray-darker;
|
||||
$dropdown-link-color: $text-color;
|
||||
$dropdown-link-hover-color: $dropdown-link-color;
|
||||
|
||||
//== Navbar
|
||||
$navbar-inverse-bg: $gray-darker;
|
||||
$navbar-inverse-link-hover-color: $text-color;
|
||||
$navbar-inverse-brand-hover-color: $navbar-inverse-link-hover-color;
|
||||
|
||||
//== Tabs
|
||||
$nav-tabs-active-link-hover-bg: $gray;
|
||||
$nav-tabs-active-link-hover-border-color: $gray-darker;
|
||||
|
||||
//== Navs
|
||||
$nav-link-hover-bg: $gray-darker;
|
||||
|
||||
//== Pagination
|
||||
$pagination-color: $light-blue;
|
||||
$pagination-bg: $gray-light;
|
||||
$pagination-border: $gray-darker;
|
||||
|
||||
$pagination-hover-color: $gray-dark;
|
||||
$pagination-hover-bg: $light-blue;
|
||||
$pagination-hover-border: $pagination-border;
|
||||
|
||||
$pagination-active-border: $pagination-border;
|
||||
|
||||
$pagination-disabled-color: $gray-dark;
|
||||
$pagination-disabled-bg: $gray-light;
|
||||
$pagination-disabled-border: $pagination-border;
|
||||
|
||||
//== Form states and alerts
|
||||
$state-success-text: lighten($green, 30%);
|
||||
$state-success-bg: darken($green, 10%);
|
||||
$state-success-border: darken($state-success-bg, 20%);
|
||||
|
||||
$state-info-text: lighten($blue, 20%);
|
||||
$state-info-bg: darken($blue, 20%);
|
||||
$state-info-border: darken($state-info-bg, 20%);
|
||||
|
||||
$state-warning-text: lighten($yellow, 30%);
|
||||
$state-warning-bg: $yellow;
|
||||
$state-warning-border: darken($state-warning-bg, 20%);
|
||||
|
||||
$state-danger-text: lighten($red, 40%);
|
||||
$state-danger-bg: $red;
|
||||
$state-danger-border: darken($state-danger-bg, 20%);
|
||||
|
||||
|
||||
//== Popovers
|
||||
$popover-bg: lighten($gray, 5%);
|
||||
$popover-border-color: $gray-darker;
|
||||
|
||||
//== Modals
|
||||
$modal-content-bg: $gray;
|
||||
$modal-header-border-color: $gray-light;
|
||||
|
||||
//== List group
|
||||
$list-group-bg: $gray;
|
||||
$list-group-link-color: $text-color;
|
||||
|
||||
//== Panels
|
||||
$panel-bg: $gray;
|
||||
$panel-default-text: $text-color;
|
||||
$panel-default-border: $gray-darker;
|
||||
$panel-default-heading-bg: $gray-dark;
|
||||
|
||||
//== Thumbnails
|
||||
$thumbnail-border: $gray-darker;
|
||||
|
||||
//== Wells
|
||||
$well-bg: $gray-dark;
|
||||
|
||||
//== Close
|
||||
$close-color: $gray-lighter;
|
||||
|
||||
//== Type
|
||||
$hr-border: $gray-light;
|
||||
|
||||
// Variables
|
||||
$text-color-pale: $gray-light;
|
||||
$text-color-active: lighten($gray-lighter, 27%);
|
||||
|
||||
$background-grey: $gray-dark;
|
||||
$background-blue: desaturate(darken($blue, 25%), 15%);
|
||||
|
||||
$border-grey: $gray-darker;
|
||||
$border-medium-grey: $gray-light;
|
||||
$border-dark-grey: darken($border-grey, 4.5%);
|
||||
|
||||
$icon-color: $text-color;
|
||||
|
||||
$main-background: $gray-dark;
|
||||
$framed-background: $gray;
|
||||
$left-navbar-drawer-background: $main-background;
|
||||
$hovercard-background: $gray;
|
||||
|
||||
@import 'color_themes/color_theme_override_dark';
|
||||
3
app/assets/stylesheets/color_themes/dark/desktop.scss
Normal file
3
app/assets/stylesheets/color_themes/dark/desktop.scss
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
@import 'mixins';
|
||||
@import 'color_themes/dark/style';
|
||||
@import 'application';
|
||||
63
app/assets/stylesheets/color_themes/dark/mobile.scss
Normal file
63
app/assets/stylesheets/color_themes/dark/mobile.scss
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
@import 'mixins';
|
||||
@import 'color_themes/dark/style';
|
||||
|
||||
// Only overriding existing selectors here, so disable some lint rules
|
||||
// scss-lint:disable SelectorFormat, NestingDepth, SelectorDepth
|
||||
body {
|
||||
.settings-container,
|
||||
.stream-element,
|
||||
.login-form {
|
||||
border: 1px solid $border-grey;
|
||||
}
|
||||
|
||||
.stream-element,
|
||||
.comments {
|
||||
.from a { color: $text-color; }
|
||||
.info { color: lighten($gray-light, 12%); }
|
||||
.nsfw-shield { background-color: $gray-light; }
|
||||
|
||||
.bottom-bar {
|
||||
background: lighten($framed-background, 4.5%);
|
||||
.post-action .disabled { color: $text-color-pale; }
|
||||
.post-stats .count { background-color: lighten($framed-background, 4.5%); }
|
||||
}
|
||||
|
||||
.reshare {
|
||||
border-bottom: 1px solid $border-medium-grey;
|
||||
.reshare_via span { color: $border-medium-grey; }
|
||||
}
|
||||
}
|
||||
|
||||
.more-link,
|
||||
.no-more-posts {
|
||||
background: { color: $btn-default-bg; }
|
||||
border: 1px solid $gray;
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
color: $text-color;
|
||||
text-shadow: 0 2px 0 $gray;
|
||||
}
|
||||
}
|
||||
|
||||
.stream-element.unread { background-color: $gray; }
|
||||
.stream-element.read { background-color: $gray-darker; }
|
||||
|
||||
.header-full-width { border-bottom: 1px solid $border-grey; }
|
||||
|
||||
.user_aspects {
|
||||
&,
|
||||
&:focus,
|
||||
&:active {
|
||||
border-color: $gray-light;
|
||||
}
|
||||
|
||||
&.has_connection {
|
||||
background-color: $green;
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
}
|
||||
// scss-lint:enable IdSelector, SelectorFormat, NestingDepth, SelectorDepth
|
||||
|
||||
@import 'mobile/mobile';
|
||||
|
|
@ -3,7 +3,6 @@ $background: #fff;
|
|||
|
||||
// Variables
|
||||
$main-background: $background;
|
||||
$sidebars-background: $background;
|
||||
$card-shadow: none;
|
||||
|
||||
@import 'color_themes/color_theme_override_origwhite';
|
||||
|
|
|
|||
|
|
@ -1,13 +1,27 @@
|
|||
.comment_stream {
|
||||
.show_comments {
|
||||
margin-top: 5px;
|
||||
border-top: 1px solid $border-grey;
|
||||
line-height: $line-height-computed;
|
||||
margin-top: 5px;
|
||||
a {
|
||||
color: $text-grey;
|
||||
font-size: 13px;
|
||||
}
|
||||
.media { margin-top: 10px; }
|
||||
}
|
||||
|
||||
.loading-comments {
|
||||
height: $line-height-computed + 11px; // height of .show_comments: line-height, 10px margin, 1px border
|
||||
margin-top: -$line-height-computed - 11px;
|
||||
|
||||
.loader {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.media { margin: 5px; }
|
||||
}
|
||||
|
||||
.comments > .comment,
|
||||
.comment.new-comment-form-wrapper {
|
||||
.avatar {
|
||||
|
|
|
|||
|
|
@ -38,13 +38,13 @@
|
|||
margin-right: 25px;
|
||||
}
|
||||
#chat_privilege_toggle > .enabled {
|
||||
color: #000;
|
||||
color: $text-color-active;
|
||||
}
|
||||
.contacts-header-icon {
|
||||
font-size: 24.5px;
|
||||
line-height: 40px;
|
||||
color: lighten($black,75%);
|
||||
&:hover { color: $black; }
|
||||
color: $text-color-pale;
|
||||
&:hover { color: $text-color; }
|
||||
}
|
||||
#suggest_member.btn { margin-top: 8px; }
|
||||
}
|
||||
|
|
@ -56,14 +56,14 @@
|
|||
font-size: 20px;
|
||||
line-height: 50px;
|
||||
margin: 0 10px;
|
||||
color: lighten($black,75%);
|
||||
&:hover { color: $black; }
|
||||
color: $text-color-pale;
|
||||
&:hover { color: $text-color; }
|
||||
}
|
||||
&.in_aspect {
|
||||
border-left: 3px solid $brand-success;
|
||||
background-color: lighten($brand-success,35%);
|
||||
}
|
||||
&:not(.in_aspect) { border-left: 3px solid $white; }
|
||||
&:not(.in_aspect) { border-left: 3px solid $framed-background; }
|
||||
}
|
||||
|
||||
.no_contacts {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
}
|
||||
|
||||
.stream-element {
|
||||
background-color: $white;
|
||||
background-color: $framed-background;
|
||||
padding: 10px;
|
||||
|
||||
.avatar {
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
.stream-element.message,
|
||||
.stream-element.new-message {
|
||||
border: 1px solid $light-grey;
|
||||
border: 1px solid $border-grey;
|
||||
box-shadow: $card-shadow;
|
||||
margin-bottom: 20px;
|
||||
|
||||
|
|
@ -83,7 +83,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.unread { background-color: darken($background-white, 5%); }
|
||||
&.unread { background-color: $background-grey; }
|
||||
&.selected { background-color: $blue; }
|
||||
|
||||
.last_author, .last_message {
|
||||
|
|
@ -183,10 +183,60 @@
|
|||
}
|
||||
// scss-lint:enable SelectorDepth
|
||||
|
||||
#new_conversation_pane {
|
||||
.new-conversation {
|
||||
ul.as-selections { width: 100% !important; }
|
||||
|
||||
input#contact_ids { box-shadow: none; }
|
||||
|
||||
label { font-weight: bold; }
|
||||
|
||||
.twitter-typeahead,
|
||||
.tt-menu {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.recipients-tag-list {
|
||||
.conversation-recipient-tag {
|
||||
background-color: $brand-primary;
|
||||
border-radius: $btn-border-radius-base;
|
||||
display: inline-flex;
|
||||
margin: 0 2px $form-group-margin-bottom;
|
||||
padding: 8px;
|
||||
|
||||
&:first-child { margin-left: 0; }
|
||||
|
||||
&:last-child { margin-right: 0; }
|
||||
|
||||
div {
|
||||
align-self: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
height: 40px;
|
||||
margin-right: 8px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.name-and-handle {
|
||||
color: $white;
|
||||
margin-right: 8px;
|
||||
text-align: left;
|
||||
|
||||
.diaspora-id { font-size: $font-size-small; }
|
||||
}
|
||||
|
||||
.entypo-circled-cross {
|
||||
color: $white;
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
|
||||
&:hover { color: $light-grey; }
|
||||
}
|
||||
}
|
||||
|
||||
.new-conversation.form-horizontal .form-group:last-of-type { margin-bottom: 0; }
|
||||
|
|
|
|||
|
|
@ -13,9 +13,7 @@ textarea {
|
|||
&:active:focus,
|
||||
&:invalid:focus,
|
||||
&:invalid:required:focus {
|
||||
border-color: $border-grey;
|
||||
box-shadow: none;
|
||||
color: $text-dark-grey;
|
||||
}
|
||||
}
|
||||
// scss-lint:enable QualifyingElement
|
||||
|
|
@ -29,7 +27,6 @@ textarea {
|
|||
margin: 20px auto;
|
||||
|
||||
fieldset {
|
||||
background-color: $white;
|
||||
margin-bottom: 1em;
|
||||
position: relative; // To correctly place the entypo icon
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@
|
|||
}
|
||||
.view_all {
|
||||
background-color: $link-color;
|
||||
border-top: 3px solid $white;
|
||||
border-top: 3px solid $dropdown-bg;
|
||||
text-align: center;
|
||||
a {
|
||||
color: $white;
|
||||
|
|
|
|||
|
|
@ -98,9 +98,9 @@ ul#help_nav {
|
|||
line-height: 70px;
|
||||
|
||||
[class^="entypo-"], [class*="entypo-"] {
|
||||
color: #bfbfbf;
|
||||
color: $text-color-pale;
|
||||
|
||||
&.entypo-chat{ color: #000000; }
|
||||
&.entypo-chat { color: $text-color-active; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@
|
|||
}
|
||||
|
||||
.landing-info-card {
|
||||
background-color: $white;
|
||||
border: 1px solid $light-grey;
|
||||
background-color: $framed-background;
|
||||
border: 1px solid $border-grey;
|
||||
box-shadow: $card-shadow;
|
||||
margin-bottom: 25px;
|
||||
margin-top: 25px;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
min-width: 250px;
|
||||
max-width: 400px;
|
||||
|
||||
background-color: $background-white;
|
||||
background-color: $hovercard-background;
|
||||
border: 1px solid $border-dark-grey;
|
||||
font-size: small;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[class^="entypo-"], [class*="entypo-"] {
|
||||
font-style: normal;
|
||||
color: black;
|
||||
color: $icon-color;
|
||||
|
||||
&.red { color: #A40802; }
|
||||
&.white { color: white; }
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
[class^="entypo-"],
|
||||
[class*="entypo-"] {
|
||||
color: $text-grey;
|
||||
color: $text-color-pale;
|
||||
font-size: $font-size-base;
|
||||
line-height: $line-height-base;
|
||||
vertical-align: middle;
|
||||
|
|
@ -12,12 +12,12 @@
|
|||
|
||||
[class^="entypo-"]:hover,
|
||||
[class*="entypo-"]:hover {
|
||||
color: $text;
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
&.hide_conversation i { font-size: $line-height-computed * 1.5; }
|
||||
&.delete_conversation i { font-size: $font-size-base * 1.5; }
|
||||
&.destroy_participation i { color: $black; }
|
||||
&.destroy_participation i { color: $text-color-active; }
|
||||
&.destroy_participation i:hover { color: $text-dark-grey; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#invite_code {
|
||||
background-color: $white;
|
||||
background-color: $framed-background;
|
||||
cursor: text;
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
|
|
@ -7,13 +7,13 @@
|
|||
|
||||
#invitationsModal {
|
||||
.modal-header, .modal-body {
|
||||
color: $text;
|
||||
color: $text-color;
|
||||
font-size: $font-size-base;
|
||||
text-align: initial;
|
||||
}
|
||||
#paste_link { font-weight: 700; }
|
||||
#invite_code { margin-top: 10px; }
|
||||
#codes_left { color: $text-grey; }
|
||||
#codes_left { color: $text-color-pale; }
|
||||
.controls { margin-left: 140px; }
|
||||
#email_invitation {
|
||||
padding-top: 10px;
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
border-top: 1px dashed $border-grey;
|
||||
label { font-weight: 700; }
|
||||
#already_sent {
|
||||
color: $text-grey;
|
||||
color: $text-color-pale;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
.md-footer,
|
||||
.md-header {
|
||||
background: $sidebars-background;
|
||||
background: $white;
|
||||
border: 0;
|
||||
display: block;
|
||||
height: 42px;
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
[class^="entypo-"],
|
||||
[class*="entypo-"],
|
||||
.glyphicon {
|
||||
color: $black;
|
||||
color: $icon-color;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +72,7 @@
|
|||
width: 18px;
|
||||
}
|
||||
|
||||
&:hover .entypo-cross { color: $text; }
|
||||
&:hover .entypo-cross { color: $text-color; }
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@
|
|||
}
|
||||
|
||||
.mentions {
|
||||
color: white;
|
||||
color: transparent;
|
||||
font-size: $font-size-base;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
overflow: hidden;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
&.active:not(.bottom_collapse),
|
||||
&.active:not(.bottom_collapse) > [class^="entypo"] {
|
||||
color: $text;
|
||||
color: $text-color;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,3 +61,5 @@
|
|||
.subject { padding: 0 10px; }
|
||||
|
||||
.message-count, .unread-message-count { margin: 10px 2px; }
|
||||
|
||||
.new-conversation .as-selections { background-color: transparent; }
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ footer {
|
|||
border-radius: 5px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
||||
|
||||
background-color: #fff;
|
||||
background-color: $framed-background;
|
||||
margin-bottom: 10px;
|
||||
|
||||
border: 1px solid #bbb;
|
||||
|
|
@ -176,7 +176,7 @@ footer {
|
|||
border-radius: 3px 3px 0 0;
|
||||
|
||||
border: {
|
||||
bottom: 1px solid #ccc;
|
||||
bottom: 1px solid $border-medium-grey;
|
||||
}
|
||||
|
||||
img.big-stream-photo {
|
||||
|
|
@ -322,7 +322,7 @@ footer {
|
|||
}
|
||||
|
||||
.header-full-width {
|
||||
background-color: #fff;
|
||||
background-color: $framed-background;
|
||||
border-bottom: 1px solid #aaa;
|
||||
margin: -10px; // Counter the #main padding
|
||||
margin-bottom: 10px;
|
||||
|
|
@ -462,7 +462,7 @@ select {
|
|||
font-weight: bold;
|
||||
color: $text-grey;
|
||||
background: {
|
||||
color: #fff;
|
||||
color: $framed-background;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ ul.followed_tags {
|
|||
margin: 0px;
|
||||
|
||||
> li {
|
||||
background-color: $white;
|
||||
background-color: $framed-background;
|
||||
border: 1px solid $border-grey;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 1px 2px rgba($border-dark-grey, 0.5);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@
|
|||
background-color: $background-grey;
|
||||
.unread-toggle {
|
||||
opacity: 1 !important;
|
||||
.entypo-eye { color: $black; }
|
||||
.entypo-eye { color: $text-color-active; }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +90,7 @@
|
|||
padding: 9px 5px;
|
||||
.entypo-eye {
|
||||
cursor: pointer;
|
||||
color: lighten($black,75%);
|
||||
color: $text-color-pale;
|
||||
font-size: 17px;
|
||||
line-height: 17px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#profile_container {
|
||||
.profile_header {
|
||||
margin-bottom: 15px;
|
||||
background-color: $white;
|
||||
background-color: $framed-background;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
padding-top: 20px;
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
font-weight: 700;
|
||||
}
|
||||
#diaspora_handle {
|
||||
color: $text-grey;
|
||||
color: $text-color-pale;
|
||||
font-size: 20px;
|
||||
}
|
||||
#sharing_message {
|
||||
|
|
@ -64,8 +64,8 @@
|
|||
.profile-header-icon {
|
||||
font-size: 24.5px;
|
||||
line-height: 30px;
|
||||
color: lighten($black,75%);
|
||||
&:hover { color: $black; }
|
||||
color: $text-color-pale;
|
||||
&:hover { color: $text-color; }
|
||||
}
|
||||
#mention_button { font-weight: 700; }
|
||||
}
|
||||
|
|
@ -80,8 +80,12 @@
|
|||
&.active {
|
||||
border-bottom: 3px solid $brand-primary;
|
||||
a {
|
||||
color: $black;
|
||||
[class^="entypo-"], [class*="entypo-"] { color: $black; }
|
||||
color: $text-color-active;
|
||||
|
||||
[class^="entypo-"],
|
||||
[class*="entypo-"] {
|
||||
color: $text-color-active;
|
||||
}
|
||||
}
|
||||
}
|
||||
a {
|
||||
|
|
@ -94,9 +98,13 @@
|
|||
margin-right: 2px;
|
||||
}
|
||||
&:hover {
|
||||
color: $black;
|
||||
[class^="entypo-"], [class*="entypo-"] { color: $black; }
|
||||
color: $text-color-active;
|
||||
text-decoration: none;
|
||||
|
||||
[class^="entypo-"],
|
||||
[class*="entypo-"] {
|
||||
color: $text-color-active;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
}
|
||||
|
||||
.captcha-input {
|
||||
border-bottom: 1px solid $border-grey;
|
||||
border-bottom: 1px solid $input-border;
|
||||
border-bottom-left-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
box-sizing: border-box;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
.sidebar,
|
||||
.framed-content {
|
||||
background-color: $white;
|
||||
border: 1px solid $light-grey;
|
||||
background-color: $framed-background;
|
||||
border: 1px solid $border-grey;
|
||||
border-top: 0;
|
||||
box-shadow: $card-shadow;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
position: relative;
|
||||
|
||||
.control-icons {
|
||||
background: $white;
|
||||
background: $framed-background;
|
||||
border-radius: 4px;
|
||||
padding-left: 4px;
|
||||
position: absolute;
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
}
|
||||
|
||||
.thumbnail {
|
||||
background: $white;
|
||||
background: $framed-background;
|
||||
border-radius: 0;
|
||||
box-shadow: $card-shadow;
|
||||
height: 240px;
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
border-color: $light-grey;
|
||||
border-color: $border-grey;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
|
@ -62,7 +62,7 @@
|
|||
|
||||
#main_stream .stream-element {
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid $light-grey;
|
||||
border: 1px solid $border-grey;
|
||||
box-shadow: $card-shadow;
|
||||
|
||||
&.highlighted {
|
||||
|
|
@ -72,7 +72,7 @@
|
|||
}
|
||||
|
||||
.stream-element {
|
||||
background-color: $white;
|
||||
background-color: $framed-background;
|
||||
padding: 10px;
|
||||
|
||||
& > .media {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,14 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="loading-comments comment text-center hidden">
|
||||
<div class="media">
|
||||
<div class="loader">
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="comments"> </div>
|
||||
|
||||
{{#if loggedIn}}
|
||||
|
|
|
|||
12
app/assets/templates/conversation_recipient_tag_tpl.jst.hbs
Normal file
12
app/assets/templates/conversation_recipient_tag_tpl.jst.hbs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<div class="conversation-recipient-tag clearfix" data-diaspora-handle="{{ handle }}">
|
||||
<div href="{{ url }}">
|
||||
<img src="{{ avatar }}" class="avatar img-responsive center-block">
|
||||
</div>
|
||||
<div class="pull-left clearfix name-and-handle" href="{{ url }}">
|
||||
<div class="name">{{ name }}</div>
|
||||
<div class="diaspora-id">{{ handle }}</div>
|
||||
</div>
|
||||
<div class="remove pull-right clearfix">
|
||||
<i class="entypo-circled-cross"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
<ul class="dropdown-menu" role="menu">
|
||||
<div class="header">
|
||||
<div class="pull-right">
|
||||
<a href="#" id="mark_all_read_link" class="btn btn-default btn-sm {{#unless current_user.notifications_count}}disabled{{/unless}}">
|
||||
<a href="#" id="mark-all-read-link" class="btn btn-default btn-sm {{#unless current_user.notifications_count}}disabled{{/unless}}">
|
||||
{{t "header.mark_all_as_read"}}
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -61,11 +61,10 @@
|
|||
{{t "header.recent_notifications"}}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="notifications">
|
||||
<div class="ajax-loader">
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
<div class="ajax-loader">
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
<div class="notifications"></div>
|
||||
<div class="view_all">
|
||||
<a href="/notifications" id="view_all_notifications">
|
||||
{{t "header.view_all"}}
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ module Api
|
|||
session[:response_type] = @response_type
|
||||
session[:redirect_uri] = @redirect_uri
|
||||
session[:scopes] = scopes_as_space_seperated_values
|
||||
session[:state] = params[:state]
|
||||
session[:nonce] = params[:nonce]
|
||||
end
|
||||
|
||||
|
|
@ -149,6 +150,7 @@ module Api
|
|||
session.delete(:response_type)
|
||||
session.delete(:redirect_uri)
|
||||
session.delete(:scopes)
|
||||
session.delete(:state)
|
||||
session.delete(:nonce)
|
||||
end
|
||||
|
||||
|
|
@ -162,6 +164,7 @@ module Api
|
|||
req.update_param("redirect_uri", session[:redirect_uri])
|
||||
req.update_param("response_type", response_type_as_space_seperated_values)
|
||||
req.update_param("scope", session[:scopes])
|
||||
req.update_param("state", session[:state])
|
||||
req.update_param("nonce", session[:nonce])
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
class Api::V1::TokensController < ApplicationController
|
||||
skip_before_filter :verify_authenticity_token
|
||||
before_filter :authenticate_user!
|
||||
|
||||
respond_to :json
|
||||
|
||||
def create
|
||||
current_user.ensure_authentication_token!
|
||||
render :status => 200, :json => { :token => current_user.authentication_token }
|
||||
end
|
||||
|
||||
def destroy
|
||||
current_user.reset_authentication_token!
|
||||
render :json => true, :status => 200
|
||||
end
|
||||
end
|
||||
|
|
@ -12,11 +12,17 @@ class CommentsController < ApplicationController
|
|||
end
|
||||
|
||||
def create
|
||||
comment = comment_service.create(params[:post_id], params[:text])
|
||||
begin
|
||||
comment = comment_service.create(params[:post_id], params[:text])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render text: I18n.t("comments.create.error"), status: 404
|
||||
return
|
||||
end
|
||||
|
||||
if comment
|
||||
respond_create_success(comment)
|
||||
else
|
||||
render nothing: true, status: 404
|
||||
render text: I18n.t("comments.create.error"), status: 422
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ class ContactsController < ApplicationController
|
|||
# Used for mentions in the publisher and pagination on the contacts page
|
||||
format.json {
|
||||
@people = if params[:q].present?
|
||||
Person.search(params[:q], current_user, only_contacts: true).limit(15)
|
||||
mutual = params[:mutual].present? && params[:mutual]
|
||||
Person.search(params[:q], current_user, only_contacts: true, mutual: mutual).limit(15)
|
||||
else
|
||||
set_up_contacts_json
|
||||
end
|
||||
|
|
|
|||
|
|
@ -30,12 +30,17 @@ class ConversationsController < ApplicationController
|
|||
end
|
||||
|
||||
def create
|
||||
contact_ids = params[:contact_ids]
|
||||
# Contacts autocomplete does not work the same way on mobile and desktop
|
||||
# Mobile returns contact ids array while desktop returns person id
|
||||
# This will have to be removed when mobile autocomplete is ported to Typeahead
|
||||
recipients_param, column = [%i(contact_ids id), %i(person_ids person_id)].find {|param, _| params[param].present? }
|
||||
if recipients_param
|
||||
person_ids = current_user.contacts.mutual.where(column => params[recipients_param].split(",")).pluck(:person_id)
|
||||
end
|
||||
|
||||
# Can't split nil
|
||||
if contact_ids
|
||||
contact_ids = contact_ids.split(',') if contact_ids.is_a? String
|
||||
person_ids = current_user.contacts.where(id: contact_ids).pluck(:person_id)
|
||||
unless person_ids.present?
|
||||
render text: I18n.t("javascripts.conversation.create.no_recipient"), status: 422
|
||||
return
|
||||
end
|
||||
|
||||
opts = params.require(:conversation).permit(:subject)
|
||||
|
|
@ -43,16 +48,12 @@ class ConversationsController < ApplicationController
|
|||
opts[:message] = { text: params[:conversation][:text] }
|
||||
@conversation = current_user.build_conversation(opts)
|
||||
|
||||
if person_ids.present? && @conversation.save
|
||||
if @conversation.save
|
||||
Diaspora::Federation::Dispatcher.defer_dispatch(current_user, @conversation)
|
||||
flash[:notice] = I18n.t("conversations.create.sent")
|
||||
render json: {id: @conversation.id}
|
||||
else
|
||||
message = I18n.t("conversations.create.fail")
|
||||
if person_ids.blank?
|
||||
message = I18n.t("javascripts.conversation.create.no_recipient")
|
||||
end
|
||||
render text: message, status: 422
|
||||
render text: I18n.t("conversations.create.fail"), status: 422
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -91,17 +92,23 @@ class ConversationsController < ApplicationController
|
|||
return
|
||||
end
|
||||
|
||||
@contacts_json = contacts_data.to_json
|
||||
@contact_ids = ""
|
||||
|
||||
if params[:contact_id]
|
||||
@contact_ids = current_user.contacts.find(params[:contact_id]).id
|
||||
elsif params[:aspect_id]
|
||||
@contact_ids = current_user.aspects.find(params[:aspect_id]).contacts.map{|c| c.id}.join(',')
|
||||
end
|
||||
if session[:mobile_view] == true && request.format.html?
|
||||
@contacts_json = contacts_data.to_json
|
||||
|
||||
@contact_ids = if params[:contact_id]
|
||||
current_user.contacts.find(params[:contact_id]).id
|
||||
elsif params[:aspect_id]
|
||||
current_user.aspects.find(params[:aspect_id]).contacts.pluck(:id).join(",")
|
||||
end
|
||||
|
||||
render :layout => true
|
||||
else
|
||||
if params[:contact_id]
|
||||
gon.push conversation_prefill: [current_user.contacts.find(params[:contact_id]).person.as_json]
|
||||
elsif params[:aspect_id]
|
||||
gon.push conversation_prefill: current_user.aspects
|
||||
.find(params[:aspect_id]).contacts.map {|c| c.person.as_json }
|
||||
end
|
||||
render :layout => false
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class LikesController < ApplicationController
|
|||
format.json { render :json => @like.as_api_response(:backbone), :status => 201 }
|
||||
end
|
||||
else
|
||||
render :nothing => true, :status => 422
|
||||
render text: I18n.t("likes.create.error"), status: 422
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ class NotificationsController < ApplicationController
|
|||
format.html
|
||||
format.xml { render :xml => @notifications.to_xml }
|
||||
format.json {
|
||||
render json: @notifications, each_serializer: NotificationSerializer
|
||||
render json: render_as_json(@unread_notification_count, @grouped_unread_notification_counts, @notifications)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
@ -82,4 +82,15 @@ class NotificationsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def render_as_json(unread_count, unread_count_by_type, notification_list)
|
||||
{
|
||||
unread_count: unread_count,
|
||||
unread_count_by_type: unread_count_by_type,
|
||||
notification_list: notification_list.map {|note|
|
||||
NotificationSerializer.new(note, default_serializer_options).as_json
|
||||
}
|
||||
}.as_json
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -14,7 +14,19 @@ class ResharesController < ApplicationController
|
|||
current_user.dispatch_post(@reshare)
|
||||
render :json => ExtremePostPresenter.new(@reshare, current_user), :status => 201
|
||||
else
|
||||
render :nothing => true, :status => 422
|
||||
render text: I18n.t("reshares.create.error"), status: 422
|
||||
end
|
||||
end
|
||||
|
||||
def index
|
||||
@reshares = target.reshares.includes(author: :profile)
|
||||
render json: @reshares.as_api_response(:backbone)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def target
|
||||
@target ||= current_user.find_visible_shareable_by_id(Post, params[:post_id]) ||
|
||||
raise(ActiveRecord::RecordNotFound.new)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,17 +7,14 @@ class ShareVisibilitiesController < ApplicationController
|
|||
before_action :authenticate_user!
|
||||
|
||||
def update
|
||||
#note :id references a postvisibility
|
||||
params[:shareable_id] ||= params[:post_id]
|
||||
params[:shareable_type] ||= 'Post'
|
||||
|
||||
vis = current_user.toggle_hidden_shareable(accessible_post)
|
||||
render :nothing => true, :status => 200
|
||||
post = post_service.find!(params[:post_id])
|
||||
current_user.toggle_hidden_shareable(post)
|
||||
head :ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def accessible_post
|
||||
@post ||= params[:shareable_type].constantize.where(:id => params[:post_id]).select("id, guid, author_id, created_at").first
|
||||
def post_service
|
||||
@post_service ||= PostService.new(current_user)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -128,6 +128,11 @@ class UsersController < ApplicationController
|
|||
redirect_to edit_user_path
|
||||
end
|
||||
|
||||
def auth_token
|
||||
current_user.ensure_authentication_token!
|
||||
render status: 200, json: {token: current_user.authentication_token}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ module ApplicationHelper
|
|||
end
|
||||
|
||||
def changelog_url
|
||||
return AppConfig.settings.changelog_url.get if AppConfig.settings.changelog_url.present?
|
||||
|
||||
url = "https://github.com/diaspora/diaspora/blob/master/Changelog.md"
|
||||
url.sub!('/master/', "/#{AppConfig.git_revision}/") if AppConfig.git_revision.present?
|
||||
url
|
||||
|
|
@ -31,14 +33,6 @@ module ApplicationHelper
|
|||
"bookmarklet('#{bookmarklet_url}', #{width}, #{height});"
|
||||
end
|
||||
|
||||
def contacts_link
|
||||
if current_user.contacts.size > 0
|
||||
contacts_path
|
||||
else
|
||||
community_spotlight_path
|
||||
end
|
||||
end
|
||||
|
||||
def all_services_connected?
|
||||
current_user.services.size == AppConfig.configured_services.size
|
||||
end
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ module LayoutHelper
|
|||
def current_user_atom_tag
|
||||
return unless @person.present?
|
||||
content_tag(:link, "", rel: "alternate", href: @person.atom_url, type: "application/atom+xml",
|
||||
title: t(".public_feed", name: @person.name))
|
||||
title: t("layouts.application.public_feed", name: @person.name))
|
||||
end
|
||||
|
||||
def translation_missing_warnings
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ module SessionsHelper
|
|||
end
|
||||
|
||||
def display_password_reset_link?
|
||||
devise_mapping.recoverable? && controller_name != "passwords"
|
||||
AppConfig.mail.enable? && devise_mapping.recoverable? && controller_name != "passwords"
|
||||
end
|
||||
|
||||
def flash_class(name)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@ module StreamHelper
|
|||
aspects_stream_path(max_time: time_for_scroll(@stream), a_ids: session[:a_ids])
|
||||
elsif current_page?(:public_stream)
|
||||
public_stream_path(max_time: time_for_scroll(@stream))
|
||||
elsif current_page?(:commented_stream)
|
||||
commented_stream_path(max_time: time_for_scroll(@stream))
|
||||
elsif current_page?(:liked_stream)
|
||||
liked_stream_path(max_time: time_for_scroll(@stream))
|
||||
elsif current_page?(:mentioned_stream)
|
||||
mentioned_stream_path(max_time: time_for_scroll(@stream))
|
||||
elsif current_page?(:followed_tags_stream)
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ class Person < ActiveRecord::Base
|
|||
[where_clause, q_tokens]
|
||||
end
|
||||
|
||||
def self.search(search_str, user, only_contacts: false)
|
||||
def self.search(search_str, user, only_contacts: false, mutual: false)
|
||||
search_str.strip!
|
||||
return none if search_str.blank? || search_str.size < 2
|
||||
|
||||
|
|
@ -159,6 +159,8 @@ class Person < ActiveRecord::Base
|
|||
).searchable(user)
|
||||
end
|
||||
|
||||
query = query.where(contacts: {sharing: true, receiving: true}) if mutual
|
||||
|
||||
query.where(closed_account: false)
|
||||
.where(sql, *tokens)
|
||||
.includes(:profile)
|
||||
|
|
|
|||
|
|
@ -61,6 +61,10 @@ class Pod < ActiveRecord::Base
|
|||
def check_all!
|
||||
Pod.find_in_batches(batch_size: 20) {|batch| batch.each(&:test_connection!) }
|
||||
end
|
||||
|
||||
def check_scheduled!
|
||||
Pod.where(scheduled_check: true).find_each(&:test_connection!)
|
||||
end
|
||||
end
|
||||
|
||||
def offline?
|
||||
|
|
@ -76,6 +80,10 @@ class Pod < ActiveRecord::Base
|
|||
"#{id}:#{host}"
|
||||
end
|
||||
|
||||
def schedule_check_if_needed
|
||||
update_column(:scheduled_check, true) if offline? && !scheduled_check
|
||||
end
|
||||
|
||||
def test_connection!
|
||||
result = ConnectionTester.check uri.to_s
|
||||
logger.debug "tested pod: '#{uri}' - #{result.inspect}"
|
||||
|
|
@ -108,6 +116,7 @@ class Pod < ActiveRecord::Base
|
|||
|
||||
attributes_from_result(result)
|
||||
touch(:checked_at)
|
||||
self.scheduled_check = false
|
||||
|
||||
save
|
||||
end
|
||||
|
|
|
|||
|
|
@ -21,6 +21,14 @@ class Reshare < Post
|
|||
self.root.update_reshares_counter if self.root.present?
|
||||
end
|
||||
|
||||
acts_as_api
|
||||
api_accessible :backbone do |t|
|
||||
t.add :id
|
||||
t.add :guid
|
||||
t.add :author
|
||||
t.add :created_at
|
||||
end
|
||||
|
||||
def root_diaspora_id
|
||||
root.try(:author).try(:diaspora_handle)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
# the COPYRIGHT file.
|
||||
|
||||
class User < ActiveRecord::Base
|
||||
include AuthenticationToken
|
||||
include Connecting
|
||||
include Querying
|
||||
include SocialActions
|
||||
|
|
@ -16,7 +17,7 @@ class User < ActiveRecord::Base
|
|||
scope :halfyear_actives, ->(time = Time.now) { logged_in_since(time - 6.month) }
|
||||
scope :active, -> { joins(:person).where(people: {closed_account: false}) }
|
||||
|
||||
devise :token_authenticatable, :database_authenticatable, :registerable,
|
||||
devise :database_authenticatable, :registerable,
|
||||
:recoverable, :rememberable, :trackable, :validatable,
|
||||
:lockable, :lastseenable, :lock_strategy => :none, :unlock_strategy => :none
|
||||
|
||||
|
|
|
|||
26
app/models/user/authentication_token.rb
Normal file
26
app/models/user/authentication_token.rb
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
class User
|
||||
module AuthenticationToken
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
# Generate new authentication token and save the record.
|
||||
def reset_authentication_token!
|
||||
self.authentication_token = self.class.authentication_token
|
||||
save(validate: false)
|
||||
end
|
||||
|
||||
# Generate authentication token unless already exists and save the record.
|
||||
def ensure_authentication_token!
|
||||
reset_authentication_token! if authentication_token.blank?
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Generate a token checking if one does not already exist in the database.
|
||||
def authentication_token
|
||||
loop do
|
||||
token = Devise.friendly_token(30)
|
||||
break token unless User.exists?(authentication_token: token)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -104,7 +104,7 @@ class PostPresenter < BasePresenter
|
|||
end
|
||||
|
||||
def user_reshare
|
||||
@post.reshare_for(current_user)
|
||||
@post.reshare_for(current_user).try(:as_api_response, :backbone)
|
||||
end
|
||||
|
||||
def already_participated_in_poll
|
||||
|
|
|
|||
30
app/views/application/_head.haml
Normal file
30
app/views/application/_head.haml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
%title
|
||||
= page_title yield(:page_title)
|
||||
|
||||
%meta{charset: "utf-8"}/
|
||||
= content_for?(:meta_data) ? yield(:meta_data) : metas_tags
|
||||
|
||||
/ favicon
|
||||
/ For Apple devices
|
||||
%link{rel: "apple-touch-icon", href: image_path("apple-touch-icon.png")}
|
||||
/ For Nokia devices
|
||||
%link{rel: "shortcut icon", href: image_path("apple-touch-icon.png")}
|
||||
/ All others
|
||||
%link{rel: "shortcut icon", href: image_path("favicon.png")}
|
||||
|
||||
- if rtl?
|
||||
= stylesheet_link_tag :rtl, media: "all"
|
||||
|
||||
- if Rails.env.test?
|
||||
= stylesheet_link_tag :poltergeist_disable_transition, media: "all"
|
||||
|
||||
= jquery_include_tag
|
||||
= include_gon(camel_case: true, nonce: content_security_policy_nonce(:script))
|
||||
= yield(:javascript)
|
||||
|
||||
= chartbeat_head_block
|
||||
= csrf_meta_tag
|
||||
= current_user_atom_tag
|
||||
= include_mixpanel
|
||||
|
||||
= yield(:head)
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
- content_for :page_title do
|
||||
= t('.title')
|
||||
= t(".title")
|
||||
|
||||
.container-fluid#contacts_container
|
||||
.row
|
||||
|
|
@ -9,33 +9,34 @@
|
|||
|
||||
.col-md-9
|
||||
.stream.contacts.framed-content#people_stream
|
||||
= render 'contacts/header'
|
||||
= render "contacts/header"
|
||||
|
||||
- if @contacts_size > 0
|
||||
- if @aspect && @aspect.contacts.length == 0
|
||||
.well
|
||||
= t('.no_contacts_in_aspect')
|
||||
= t(".no_contacts_in_aspect")
|
||||
#contact_stream
|
||||
-# JS
|
||||
|
||||
- else
|
||||
.no_contacts
|
||||
%h3
|
||||
= t('.no_contacts')
|
||||
= t(".no_contacts")
|
||||
- if AppConfig.settings.community_spotlight.enable?
|
||||
%p
|
||||
!= t(".no_contacts_message",
|
||||
community_spotlight: link_to(t(".community_spotlight"), community_spotlight_path))
|
||||
%p
|
||||
!= t('.no_contacts_message',
|
||||
:community_spotlight => link_to(t('.community_spotlight'), community_spotlight_path))
|
||||
%p
|
||||
.btn.btn-link{ 'data-toggle' => 'modal' }
|
||||
= t('invitations.new.invite_someone_to_join')
|
||||
.btn.btn-link{"data-toggle" => "modal"}
|
||||
= t("invitations.new.invite_someone_to_join")
|
||||
|
||||
#paginate
|
||||
.loader.hidden
|
||||
.spinner
|
||||
|
||||
-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'
|
||||
.conversations-form-container#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"
|
||||
|
|
|
|||
|
|
@ -2,9 +2,13 @@
|
|||
= form_for Conversation.new, html: {id: "new-conversation",
|
||||
class: "new-conversation form-horizontal"}, remote: true do |conversation|
|
||||
.form-group
|
||||
%label#toLabel{for: "contact_ids"}
|
||||
= t(".to")
|
||||
= text_field_tag "contact_autocomplete", nil, id: "contact-autocomplete", class: "form-control"
|
||||
%label#to-label{for: "contacts-search-input"}= t(".to")
|
||||
.recipients-tag-list.clearfix#recipients-tag-list
|
||||
= text_field_tag "contact_autocomplete", nil, id: "contacts-search-input", class: "form-control"
|
||||
- unless defined?(mobile) && mobile
|
||||
= text_field_tag "person_ids", nil, id: "contact-ids", type: "hidden",
|
||||
aria: {labelledby: "to-label"}
|
||||
|
||||
.form-group
|
||||
%label#subject-label{for: "conversation-subject"}
|
||||
= t(".subject")
|
||||
|
|
@ -14,12 +18,14 @@
|
|||
aria: {labelledby: "subject-label"},
|
||||
value: "",
|
||||
placeholder: t("conversations.new.subject_default")
|
||||
|
||||
.form-group
|
||||
%label.sr-only#message-label{for: "new-message-text"} = t(".message")
|
||||
%label.sr-only#message-label{for: "new-message-text"}= t(".message")
|
||||
= text_area_tag "conversation[text]", "",
|
||||
rows: 5,
|
||||
id: "new-message-text",
|
||||
class: "conversation-message-text input-block-level form-control",
|
||||
aria: {labelledby: "message-label"}
|
||||
|
||||
.form-group
|
||||
= conversation.submit t(".send"), "data-disable-with" => t(".sending"), :class => "btn btn-primary pull-right"
|
||||
|
|
|
|||
|
|
@ -25,5 +25,4 @@
|
|||
- for participant in conversation.participants
|
||||
= person_image_link(participant, :size => :thumb_small)
|
||||
|
||||
.stream
|
||||
= render partial: 'messages', locals: { conversation: conversation }
|
||||
= render partial: "messages", locals: {conversation: conversation}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,2 @@
|
|||
:javascript
|
||||
$(document).ready(function () {
|
||||
var data = $.parseJSON( "#{escape_javascript(@contacts_json)}" );
|
||||
new app.views.ConversationsForm({
|
||||
el: $("form#new-conversation").parent(),
|
||||
contacts: data,
|
||||
prefillName: "#{h params[:name]}",
|
||||
prefillValue: "#{@contact_ids}"
|
||||
});
|
||||
});
|
||||
|
||||
= include_gon camel_case: true
|
||||
= render 'conversations/new'
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
:plain
|
||||
$(document).ready(function () {
|
||||
var data = $.parseJSON( "#{escape_javascript(@contacts_json).html_safe}" ),
|
||||
autocompleteInput = $("#contact-autocomplete");
|
||||
autocompleteInput = $("#contacts-search-input");
|
||||
|
||||
autocompleteInput.autoSuggest(data, {
|
||||
selectedItemProp: "name",
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
retrieveLimit: 10,
|
||||
minChars: 1,
|
||||
keyDelay: 0,
|
||||
startText: '',
|
||||
startText: "",
|
||||
emptyText: "#{t("no_results")}",
|
||||
preFill: [{name : "#{h params[:name]}",
|
||||
value : "#{@contact_ids}"}]
|
||||
|
|
@ -27,6 +27,6 @@
|
|||
#flash-messages
|
||||
.container-fluid.row
|
||||
%h3
|
||||
= t('conversations.index.new_conversation')
|
||||
= t("conversations.index.new_conversation")
|
||||
|
||||
= render 'conversations/new'
|
||||
= render "conversations/new", mobile: true
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
- if controller_name != 'sessions'
|
||||
= link_to t('.sign_in'), new_session_path(resource_name)
|
||||
%br/
|
||||
- if AppConfig.settings.enable_registrations? && devise_mapping.registerable? && controller_name != 'registrations'
|
||||
- if display_registration_link?
|
||||
= link_to t('.sign_up'), new_registration_path(resource_name)
|
||||
%br/
|
||||
- else
|
||||
%b= t('.sign_up_closed')
|
||||
%br/
|
||||
- if devise_mapping.recoverable? && controller_name != 'passwords'
|
||||
- if display_password_reset_link?
|
||||
= link_to t('.forgot_your_password'), new_password_path(resource_name)
|
||||
%br/
|
||||
- if devise_mapping.confirmable? && controller_name != 'confirmations'
|
||||
|
|
|
|||
|
|
@ -1,32 +1,33 @@
|
|||
#paste_link
|
||||
= t('.paste_link')
|
||||
= t(".paste_link")
|
||||
%span#codes_left
|
||||
= "(" + t(".codes_left", count: @invite_code.count) + ")" unless AppConfig.settings.enable_registrations?
|
||||
.form-horizontal
|
||||
.control-group
|
||||
= invite_link(@invite_code)
|
||||
|
||||
#email_invitation
|
||||
= form_tag new_user_invitation_path, class: 'form-horizontal' do
|
||||
- if AppConfig.mail.enable?
|
||||
#email_invitation
|
||||
= form_tag new_user_invitation_path, class: "form-horizontal" do
|
||||
|
||||
.form-group
|
||||
%label.col-sm-2.control-label{ for: 'email_inviter_emails' }
|
||||
= t('email')
|
||||
.col-sm-10
|
||||
= text_field_tag 'email_inviter[emails]', @invalid_emails, title: t('.comma_separated_plz'),
|
||||
placeholder: 'foo@bar.com, max@foo.com...', class: "form-control"
|
||||
#already_sent
|
||||
= t("invitations.create.note_already_sent", emails: @valid_emails) unless @valid_emails.empty?
|
||||
.form-group
|
||||
%label.col-sm-2.control-label{for: "email_inviter_emails"}
|
||||
= t("email")
|
||||
.col-sm-10
|
||||
= text_field_tag "email_inviter[emails]", @invalid_emails, title: t(".comma_separated_plz"),
|
||||
placeholder: "foo@bar.com, max@foo.com...", class: "form-control"
|
||||
#already_sent
|
||||
= t("invitations.create.note_already_sent", emails: @valid_emails) unless @valid_emails.empty?
|
||||
|
||||
.form-group
|
||||
%label.col-sm-2.control-label{ for: 'email_inviter_locale' }
|
||||
= t('.language')
|
||||
.col-sm-10
|
||||
= select_tag 'email_inviter[locale]', options_from_collection_for_select(available_language_options,
|
||||
"second", "first", selected: current_user.language), class: "form-control"
|
||||
.form-group
|
||||
%label.col-sm-2.control-label{for: "email_inviter_locale"}
|
||||
= t(".language")
|
||||
.col-sm-10
|
||||
= select_tag "email_inviter[locale]", options_from_collection_for_select(available_language_options,
|
||||
"second", "first", selected: current_user.language), class: "form-control"
|
||||
|
||||
.form-group
|
||||
.pull-right.col-md-12
|
||||
= submit_tag t('.send_an_invitation'), class: 'btn btn-primary pull-right',
|
||||
data: {disable_with: t('.sending_invitation')}
|
||||
.clearfix
|
||||
.form-group
|
||||
.pull-right.col-md-12
|
||||
= submit_tag t(".send_an_invitation"), class: "btn btn-primary pull-right",
|
||||
data: {disable_with: t(".sending_invitation")}
|
||||
.clearfix
|
||||
|
|
|
|||
|
|
@ -3,47 +3,25 @@
|
|||
-# the COPYRIGHT file.
|
||||
|
||||
!!!
|
||||
%html{lang: I18n.locale.to_s, dir: (rtl?) ? 'rtl' : 'ltr'}
|
||||
%html{lang: I18n.locale.to_s, dir: (rtl? ? "rtl" : "ltr")}
|
||||
%head{prefix: og_prefix}
|
||||
%title
|
||||
= page_title yield(:page_title)
|
||||
%meta{name: "viewport", content: "width=device-width, initial-scale=1"}/
|
||||
|
||||
%meta{charset: 'utf-8'}/
|
||||
%meta{name: "viewport", content: "width=device-width, initial-scale=1"}/
|
||||
= content_for?(:meta_data) ? yield(:meta_data) : metas_tags
|
||||
- content_for :javascript do
|
||||
= old_browser_js_support
|
||||
|
||||
%link{rel: 'shortcut icon', href: "#{image_path('favicon.png')}" }
|
||||
<!--[if IE]>
|
||||
= javascript_include_tag :ie
|
||||
<![endif]-->
|
||||
|
||||
= chartbeat_head_block
|
||||
= include_mixpanel
|
||||
= javascript_include_tag :main, :templates
|
||||
= load_javascript_locales
|
||||
|
||||
= render "head"
|
||||
= include_color_theme
|
||||
|
||||
- if rtl?
|
||||
= stylesheet_link_tag :rtl, media: 'all'
|
||||
|
||||
- if Rails.env.test?
|
||||
= stylesheet_link_tag :poltergeist_disable_transition, media: "all"
|
||||
|
||||
= old_browser_js_support
|
||||
<!--[if IE]>
|
||||
= javascript_include_tag :ie
|
||||
<![endif]-->
|
||||
|
||||
= jquery_include_tag
|
||||
= javascript_include_tag :main, :templates
|
||||
= load_javascript_locales
|
||||
|
||||
= translation_missing_warnings
|
||||
= current_user_atom_tag
|
||||
|
||||
= yield(:head)
|
||||
= csrf_meta_tag
|
||||
|
||||
|
||||
= include_gon(camel_case: true, nonce: content_security_policy_nonce(:script))
|
||||
|
||||
%body{ class: "page-#{controller_name} action-#{action_name}" }
|
||||
%body{class: "page-#{controller_name} action-#{action_name}"}
|
||||
= yield :before_content
|
||||
|
||||
%noscript
|
||||
|
|
|
|||
|
|
@ -3,56 +3,25 @@
|
|||
-# the COPYRIGHT file.
|
||||
|
||||
!!!
|
||||
%html{:lang => I18n.locale.to_s, :dir => (rtl?) ? 'rtl' : 'ltr'}
|
||||
%head
|
||||
%title
|
||||
= pod_name
|
||||
%html{lang: I18n.locale.to_s, dir: (rtl? ? "rtl" : "ltr")}
|
||||
%head{prefix: og_prefix}
|
||||
- content_for :javascript do
|
||||
= javascript_include_tag "mobile/mobile"
|
||||
= load_javascript_locales
|
||||
|
||||
%meta{:name => "description", :content => "diaspora* mobile"}/
|
||||
%meta{:name => "author", :content => "Diaspora, Inc."}/
|
||||
%meta{:charset => 'utf-8'}/
|
||||
= render "head"
|
||||
= include_color_theme "mobile"
|
||||
|
||||
/ Viewport scale
|
||||
%meta{:name =>'viewport', :content => "width=device-width, minimum-scale=1 maximum-scale=1"}/
|
||||
%meta{:name => "HandheldFriendly", :content => "True"}/
|
||||
%meta{:name => "MobileOptimized", :content => "320"}/
|
||||
/ Force cleartype on WP7
|
||||
%meta{'http-equiv' => "cleartype", :content => 'on'}/
|
||||
|
||||
/ Home screen icon (sized for retina displays)
|
||||
%link{rel: "apple-touch-icon", href: image_path("apple-touch-icon.png")}
|
||||
/ For Nokia devices
|
||||
%link{rel: "shortcut icon", href: image_path("apple-touch-icon.png")}
|
||||
/ For desktop
|
||||
%link{rel: 'shortcut icon', href: image_path("favicon.png")}
|
||||
%meta{name: "viewport", content: "width=device-width, minimum-scale=1 maximum-scale=1"}/
|
||||
%meta{name: "HandheldFriendly", content: "True"}/
|
||||
%meta{name: "MobileOptimized", content: "320"}/
|
||||
%meta{"http-equiv" => "cleartype", :content => "on"}/
|
||||
|
||||
/ iOS mobile web app indicator
|
||||
/ NOTE(we will enable these once we don't have to rely on back/forward buttons anymore)
|
||||
/%meta{:name => "apple-mobile-web-app-capable", :content => "yes"}
|
||||
/%link{:rel => "apple-touch-startup-image", :href => "/images/apple-splash.png"}
|
||||
= yield :meta_data
|
||||
|
||||
= chartbeat_head_block
|
||||
|
||||
/ Stylesheets
|
||||
|
||||
= include_color_theme "mobile"
|
||||
= yield(:custom_css)
|
||||
|
||||
|
||||
= csrf_meta_tag
|
||||
|
||||
- if rtl?
|
||||
= stylesheet_link_tag :rtl, :media => 'all'
|
||||
|
||||
- if Rails.env.test?
|
||||
= stylesheet_link_tag :poltergeist_disable_transition, media: "all"
|
||||
|
||||
= jquery_include_tag
|
||||
|
||||
= yield(:head)
|
||||
|
||||
= include_gon(camel_case: true, nonce: content_security_policy_nonce(:script))
|
||||
%body
|
||||
#app
|
||||
= render "layouts/header"
|
||||
|
|
@ -62,10 +31,8 @@
|
|||
#main{:role => "main"}
|
||||
- if current_page?(:activity_stream)
|
||||
%h3
|
||||
= t('streams.activity.title')
|
||||
= t("streams.activity.title")
|
||||
= yield
|
||||
|
||||
/ javascripts at the bottom
|
||||
= javascript_include_tag "mobile/mobile"
|
||||
= load_javascript_locales
|
||||
= include_chartbeat
|
||||
= include_mixpanel_guid
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
= t(".notifications")
|
||||
.list-group
|
||||
%a.list-group-item{href: "/notifications" + (params[:show] == "unread" ? "?show=unread" : ""),
|
||||
class: ("active" unless params[:type] && @grouped_unread_notification_counts.has_key?(params[:type]))}
|
||||
class: ("active" unless params[:type] && @grouped_unread_notification_counts.has_key?(params[:type])),
|
||||
data: {type: "all"}}
|
||||
%span.pull-right.badge{class: ("hidden" unless @unread_notification_count > 0)}
|
||||
= @unread_notification_count
|
||||
= t(".all_notifications")
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
id: 'mentionModal'
|
||||
|
||||
-if @contact
|
||||
#new_conversation_pane
|
||||
.conversations-form-container#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'),
|
||||
|
|
|
|||
|
|
@ -1,21 +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.
|
||||
|
||||
- content_for :head do
|
||||
= javascript_include_tag :photos
|
||||
|
||||
#author_info
|
||||
= person_image_link(post.author, :size => :thumb_small)
|
||||
.from
|
||||
%h2
|
||||
= post.author_name
|
||||
|
||||
#show_photo{:data=>{:guid=>post.id}}
|
||||
= image_tag post.url(:scaled_full)
|
||||
|
||||
#caption
|
||||
= post.text
|
||||
|
||||
%br
|
||||
= link_to t('photos.show.show_original_post'), post_path(post.status_message)
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
= t(".share_this")
|
||||
= invite_link(current_user.invitation_code)
|
||||
.invitations-link.btn.btn-link#invitations-button{"data-toggle" => "modal"}
|
||||
= t(".by_email")
|
||||
|
||||
= render "shared/modal",
|
||||
path: new_user_invitation_path,
|
||||
id: "invitationsModal",
|
||||
title: t("invitations.new.invite_someone_to_join")
|
||||
- if AppConfig.mail.enable?
|
||||
.invitations-link.btn.btn-link#invitations-button{"data-toggle" => "modal"}
|
||||
= t(".by_email")
|
||||
|
||||
- content_for :after_content do
|
||||
= render "shared/modal",
|
||||
path: new_user_invitation_path,
|
||||
id: "invitationsModal",
|
||||
title: t("invitations.new.invite_someone_to_join")
|
||||
|
|
|
|||
|
|
@ -117,58 +117,59 @@
|
|||
|
||||
= render partial: "post_default"
|
||||
|
||||
.row
|
||||
.col-md-12
|
||||
%h3
|
||||
= t(".receive_email_notifications")
|
||||
= form_for "user", url: edit_user_path, html: {method: :put} do |f|
|
||||
= f.fields_for :email_preferences do |type|
|
||||
#email_prefs
|
||||
- if current_user.admin?
|
||||
= type.label :someone_reported, class: "checkbox-inline" do
|
||||
= type.check_box :someone_reported, {checked: @email_prefs["someone_reported"]}, false, true
|
||||
= t(".someone_reported")
|
||||
- if AppConfig.mail.enable?
|
||||
.row
|
||||
.col-md-12
|
||||
%h3
|
||||
= t(".receive_email_notifications")
|
||||
= form_for "user", url: edit_user_path, html: {method: :put} do |f|
|
||||
= f.fields_for :email_preferences do |type|
|
||||
#email_prefs
|
||||
- if current_user.admin?
|
||||
= type.label :someone_reported, class: "checkbox-inline" do
|
||||
= type.check_box :someone_reported, {checked: @email_prefs["someone_reported"]}, false, true
|
||||
= t(".someone_reported")
|
||||
|
||||
.small-horizontal-spacer
|
||||
.small-horizontal-spacer
|
||||
|
||||
= type.label :started_sharing, class: "checkbox-inline" do
|
||||
= type.check_box :started_sharing, {checked: @email_prefs["started_sharing"]}, false, true
|
||||
= t(".started_sharing")
|
||||
.small-horizontal-spacer
|
||||
= type.label :started_sharing, class: "checkbox-inline" do
|
||||
= type.check_box :started_sharing, {checked: @email_prefs["started_sharing"]}, false, true
|
||||
= t(".started_sharing")
|
||||
.small-horizontal-spacer
|
||||
|
||||
= type.label :mentioned, class: "checkbox-inline" do
|
||||
= type.check_box :mentioned, {checked: @email_prefs["mentioned"]}, false, true
|
||||
= t(".mentioned")
|
||||
.small-horizontal-spacer
|
||||
= type.label :mentioned, class: "checkbox-inline" do
|
||||
= type.check_box :mentioned, {checked: @email_prefs["mentioned"]}, false, true
|
||||
= t(".mentioned")
|
||||
.small-horizontal-spacer
|
||||
|
||||
= type.label :liked, class: "checkbox-inline" do
|
||||
= type.check_box :liked, {checked: @email_prefs["liked"]}, false, true
|
||||
= t(".liked")
|
||||
.small-horizontal-spacer
|
||||
= type.label :liked, class: "checkbox-inline" do
|
||||
= type.check_box :liked, {checked: @email_prefs["liked"]}, false, true
|
||||
= t(".liked")
|
||||
.small-horizontal-spacer
|
||||
|
||||
= type.label :reshared, class: "checkbox-inline" do
|
||||
= type.check_box :reshared, {checked: @email_prefs["reshared"]}, false, true
|
||||
= t(".reshared")
|
||||
.small-horizontal-spacer
|
||||
= type.label :reshared, class: "checkbox-inline" do
|
||||
= type.check_box :reshared, {checked: @email_prefs["reshared"]}, false, true
|
||||
= t(".reshared")
|
||||
.small-horizontal-spacer
|
||||
|
||||
= type.label :comment_on_post, class: "checkbox-inline" do
|
||||
= type.check_box :comment_on_post, {checked: @email_prefs["comment_on_post"]}, false, true
|
||||
= t(".comment_on_post")
|
||||
.small-horizontal-spacer
|
||||
= type.label :comment_on_post, class: "checkbox-inline" do
|
||||
= type.check_box :comment_on_post, {checked: @email_prefs["comment_on_post"]}, false, true
|
||||
= t(".comment_on_post")
|
||||
.small-horizontal-spacer
|
||||
|
||||
= type.label :also_commented, class: "checkbox-inline" do
|
||||
= type.check_box :also_commented, {checked: @email_prefs["also_commented"]}, false, true
|
||||
= t(".also_commented")
|
||||
.small-horizontal-spacer
|
||||
= type.label :also_commented, class: "checkbox-inline" do
|
||||
= type.check_box :also_commented, {checked: @email_prefs["also_commented"]}, false, true
|
||||
= t(".also_commented")
|
||||
.small-horizontal-spacer
|
||||
|
||||
= type.label :private_message, class: "checkbox-inline" do
|
||||
= type.check_box :private_message, {checked: @email_prefs["private_message"]}, false, true
|
||||
= t(".private_message")
|
||||
= type.label :private_message, class: "checkbox-inline" do
|
||||
= type.check_box :private_message, {checked: @email_prefs["private_message"]}, false, true
|
||||
= t(".private_message")
|
||||
|
||||
.small-horizontal-spacer
|
||||
.small-horizontal-spacer
|
||||
|
||||
.clearfix= f.submit t(".change"), class: "btn btn-primary pull-right", id: "change_email_preferences"
|
||||
%hr
|
||||
.clearfix= f.submit t(".change"), class: "btn btn-primary pull-right", id: "change_email_preferences"
|
||||
%hr
|
||||
|
||||
.row
|
||||
.col-md-6#account_data
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue