mirror of
https://github.com/diaspora/diaspora.git
synced 2026-01-09 15:18:11 -05:00
Move Javascript to the asset pipeline
* Move all Diaspora-specific javascripts to app/assets/javascripts * Move all vendored javascripts to vendor/assets/javascripts * Add the appropriate Sprockets require directives to make sure everything gets included in the right order * Remove Jammit dependencies * Fix all templates that were using Jammit's include_javascripts helper * Add handlebars_assets gem for compiling Handlebars templates * Move all Handlebars templates to app/assets/templates and rename from .handlebars to .jst.hbs (this is to keep them in the same global JST namespace that they were in under Jammit) * Add public/assets to .gitignore since these files can and should be re-generated by Heroku or Capistrano during each deploy * Fix a few Handlebars templates that were looking for images in the wrong location (I'm sure there are others, but it's late) * Configure application.rb to precompile all javascript and css assets that were compiled by Jammit in the Rails 3.0 code
This commit is contained in:
committed by
Maxwell Salzberg
parent
9dffb426d4
commit
1aa0b15c8c
@@ -1,46 +0,0 @@
|
||||
var app = {
|
||||
collections: {},
|
||||
models: {},
|
||||
helpers: {},
|
||||
views: {},
|
||||
pages: {},
|
||||
forms: {},
|
||||
|
||||
user: function(userAttrs) {
|
||||
if(userAttrs) { return this._user = new app.models.User(userAttrs) }
|
||||
return this._user || false
|
||||
},
|
||||
|
||||
baseImageUrl: function(baseUrl){
|
||||
if(baseUrl) { return this._baseImageUrl = baseUrl }
|
||||
return this._baseImageUrl || ""
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
app.router = new app.Router();
|
||||
|
||||
app.currentUser = app.user(window.current_user_attributes) || new app.models.User()
|
||||
|
||||
if(app.currentUser.authenticated()){
|
||||
app.header = new app.views.Header;
|
||||
$("header").prepend(app.header.el);
|
||||
app.header.render();
|
||||
}
|
||||
|
||||
|
||||
Backbone.history.start({pushState: true});
|
||||
|
||||
// there's probably a better way to do this...
|
||||
$("a[rel=backbone]").bind("click", function(evt){
|
||||
evt.preventDefault();
|
||||
var link = $(this);
|
||||
|
||||
$(".stream_title").text(link.text())
|
||||
app.router.navigate(link.attr("href").substring(1) ,true)
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
$(function() {
|
||||
app.initialize();
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
app.collections.Comments = Backbone.Collection.extend({
|
||||
model: app.models.Comment,
|
||||
|
||||
initialize : function(models, options) {
|
||||
this.url = "/posts/" + options.post.id + "/comments" //not delegating to post.url() because when it is in a stream collection it delegates to that url
|
||||
}
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
app.collections.Likes = Backbone.Collection.extend({
|
||||
model: app.models.Like,
|
||||
|
||||
initialize : function(models, options) {
|
||||
this.url = "/posts/" + options.post.id + "/likes" //not delegating to post.url() because when it is in a stream collection it delegates to that url
|
||||
}
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
app.collections.Participations = Backbone.Collection.extend({
|
||||
model: app.models.Participation,
|
||||
|
||||
initialize : function(models, options) {
|
||||
this.url = "/posts/" + options.post.id + "/participations" //not delegating to post.url() because when it is in a stream collection it delegates to that url
|
||||
}
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
app.collections.Photos = Backbone.Collection.extend({
|
||||
url : "/photos",
|
||||
|
||||
model: function(attrs, options) {
|
||||
var modelClass = app.models.Photo
|
||||
return new modelClass(attrs, options);
|
||||
},
|
||||
|
||||
parse: function(resp){
|
||||
return resp.photos;
|
||||
}
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
app.collections.Posts = Backbone.Collection.extend({
|
||||
url : "/posts",
|
||||
|
||||
model: function(attrs, options) {
|
||||
var modelClass = app.models[attrs.post_type] || app.models.Post
|
||||
return new modelClass(attrs, options);
|
||||
},
|
||||
|
||||
parse: function(resp){
|
||||
return resp.posts;
|
||||
}
|
||||
});
|
||||
@@ -1,35 +0,0 @@
|
||||
(function(){
|
||||
var dateFormatter = function dateFormatter() {
|
||||
|
||||
};
|
||||
|
||||
dateFormatter.parse = function(date_string) {
|
||||
var timestamp = new Date(date_string).getTime();
|
||||
|
||||
if (isNaN(timestamp)) {
|
||||
timestamp = dateFormatter.parseISO8601UTC(date_string);
|
||||
}
|
||||
|
||||
return timestamp;
|
||||
},
|
||||
|
||||
dateFormatter.parseISO8601UTC = function(date_string) {
|
||||
var iso8601_utc_pattern = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(.(\d{3}))?Z$/;
|
||||
var time_components = date_string.match(iso8601_utc_pattern);
|
||||
var timestamp = 0;
|
||||
|
||||
if (time_components != null) {
|
||||
if (time_components[8] == undefined) {
|
||||
time_components[8] = 0;
|
||||
}
|
||||
|
||||
timestamp = Date.UTC(time_components[1], time_components[2] - 1, time_components[3],
|
||||
time_components[4], time_components[5], time_components[6],
|
||||
time_components[8]);
|
||||
}
|
||||
|
||||
return timestamp;
|
||||
},
|
||||
|
||||
app.helpers.dateFormatter = dateFormatter;
|
||||
})();
|
||||
@@ -1,26 +0,0 @@
|
||||
Handlebars.registerHelper('t', function(scope, values) {
|
||||
return Diaspora.I18n.t(scope, values.hash)
|
||||
})
|
||||
|
||||
Handlebars.registerHelper('imageUrl', function(path){
|
||||
return app.baseImageUrl() + path;
|
||||
})
|
||||
|
||||
Handlebars.registerHelper('linkToPerson', function(context, block) {
|
||||
var html = "<a href=\"/people/" + context.guid + "\" class=\"author-name\">";
|
||||
html+= block.fn(context);
|
||||
html+= "</a>";
|
||||
|
||||
return html
|
||||
})
|
||||
|
||||
Handlebars.registerHelper('personImage', function(person, size, imageClass) {
|
||||
/* we return here if person.avatar is blank, because this happens when a
|
||||
* user is unauthenticated. we don't know why this happens... */
|
||||
if(typeof(person.avatar) == "undefined") { return }
|
||||
|
||||
size = (typeof(size) != "string" ? "small" : size);
|
||||
imageClass = (typeof(imageClass) != "string" ? size : imageClass);
|
||||
|
||||
return "<img src=\"" + person.avatar[size] +"\" class=\"avatar " + imageClass + "\" title=\"" + person.name +"\" />";
|
||||
})
|
||||
@@ -1,4 +0,0 @@
|
||||
/* we need to wrap this in a document ready to ensure JST is accessible */
|
||||
$(function(){
|
||||
Handlebars.registerPartial('status-message', JST['status-message'])
|
||||
});
|
||||
@@ -1,69 +0,0 @@
|
||||
(function(){
|
||||
var textFormatter = function textFormatter(model) {
|
||||
var text = model.get("text");
|
||||
var mentions = model.get("mentioned_people");
|
||||
|
||||
return textFormatter.mentionify(
|
||||
textFormatter.hashtagify(
|
||||
textFormatter.markdownify(text)
|
||||
), mentions
|
||||
)
|
||||
};
|
||||
|
||||
textFormatter.markdownify = function markdownify(text){
|
||||
var converter = Markdown.getSanitizingConverter();
|
||||
|
||||
// punycode non-ascii chars in urls
|
||||
converter.hooks.chain("preConversion", function(text) {
|
||||
|
||||
// add < > around plain urls, effectively making them "autolinks"
|
||||
var urlRegex = /(^|\s)\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/gi;
|
||||
text = text.replace(urlRegex, function(wholematch, space, url) {
|
||||
return space+"<"+url+">";
|
||||
});
|
||||
|
||||
// process links
|
||||
var linkRegex = /(\[.*\]:\s)?(<|\()(((https?|ftp):\/{1,3})([^'">\s]+))(>|\))/gi;
|
||||
text = text.replace(linkRegex, function() {
|
||||
var protocol = arguments[4];
|
||||
var unicodeUrl = arguments[6];
|
||||
var asciiUrl = protocol+punycode.toASCII(unicodeUrl);
|
||||
if( !arguments[1] || arguments[1] == "") { // inline link
|
||||
if(arguments[2] == "<") return "["+protocol+unicodeUrl+"]("+asciiUrl+")"; // without link text
|
||||
else return arguments[2]+asciiUrl+arguments[7]; // with link text
|
||||
} else { // reference style link
|
||||
return arguments[1]+asciiUrl;
|
||||
}
|
||||
});
|
||||
|
||||
return text;
|
||||
});
|
||||
|
||||
converter.hooks.chain("postConversion", function (text) {
|
||||
return text.replace(/(\"(?:(?:http|https):\/\/)?[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(?:\/\S*)?\")(\>)/g, '$1 target="_blank">')
|
||||
});
|
||||
|
||||
return converter.makeHtml(text)
|
||||
};
|
||||
|
||||
textFormatter.hashtagify = function hashtagify(text){
|
||||
var utf8WordCharcters =/(\s|^|>)#([\u0080-\uFFFF|\w|-]+|<3)/g
|
||||
return text.replace(utf8WordCharcters, function(hashtag, preceeder, tagText) {
|
||||
return preceeder + "<a href='/tags/" + tagText + "' class='tag'>#" + tagText + "</a>"
|
||||
})
|
||||
};
|
||||
|
||||
textFormatter.mentionify = function mentionify(text, mentions) {
|
||||
var mentionRegex = /@\{([^;]+); ([^\}]+)\}/g
|
||||
return text.replace(mentionRegex, function(mentionText, fullName, diasporaId) {
|
||||
var person = _.find(mentions, function(person){
|
||||
return person.diaspora_id == diasporaId
|
||||
})
|
||||
|
||||
return person ? "<a href='/people/" + person.guid + "' class='mention'>" + fullName + "</a>" : fullName;
|
||||
})
|
||||
}
|
||||
|
||||
app.helpers.textFormatter = textFormatter;
|
||||
})();
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
app.models.Block = Backbone.Model.extend({
|
||||
urlRoot : "/blocks"
|
||||
});
|
||||
@@ -1,3 +0,0 @@
|
||||
app.models.Comment = Backbone.Model.extend({
|
||||
urlRoot: "/comments"
|
||||
});
|
||||
@@ -1 +0,0 @@
|
||||
app.models.Like = Backbone.Model.extend({ });
|
||||
@@ -1 +0,0 @@
|
||||
app.models.Participation = Backbone.Model.extend({ });
|
||||
@@ -1,14 +0,0 @@
|
||||
app.models.Photo = Backbone.Model.extend({
|
||||
urlRoot : "/photos",
|
||||
|
||||
initialize : function() {},
|
||||
|
||||
createdAt : function() {
|
||||
return this.timeOf("created_at");
|
||||
},
|
||||
|
||||
timeOf: function(field) {
|
||||
return app.helpers.dateFormatter.parse(this.get(field)) / 1000;
|
||||
},
|
||||
|
||||
});
|
||||
@@ -1,69 +0,0 @@
|
||||
app.models.Photos = Backbone.Model.extend({
|
||||
initialize : function(){
|
||||
this.photos = new app.collections.Photos([], this.photoOptions());
|
||||
},
|
||||
|
||||
photoOptions :function(){
|
||||
var order = this.sortOrder();
|
||||
return {
|
||||
comparator : function(photo) { return -photo[order](); }
|
||||
}
|
||||
},
|
||||
|
||||
url : function() {
|
||||
return _.any(this.photos.models) ? this.timeFilteredPath() : this.basePath()
|
||||
},
|
||||
|
||||
_fetching : false,
|
||||
|
||||
fetch : function(){
|
||||
if(this._fetching) { return false; }
|
||||
var self = this;
|
||||
|
||||
// we're fetching the collection... there is probably a better way to do this
|
||||
self._fetching = true;
|
||||
|
||||
this.photos
|
||||
.fetch({
|
||||
add : true,
|
||||
url : self.url()
|
||||
})
|
||||
.done(
|
||||
function(resp){
|
||||
// we're done fetching... there is probably a better way to handle this
|
||||
self._fetching = false;
|
||||
|
||||
self.trigger("fetched", self);
|
||||
|
||||
// all loaded?
|
||||
if(resp.photos && resp.photos.length == 0) {
|
||||
self.trigger("allPostsLoaded", self);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
basePath : function(){
|
||||
return document.location.pathname;
|
||||
},
|
||||
|
||||
timeFilteredPath : function(){
|
||||
return this.basePath() + "?max_time=" + this.maxTime();
|
||||
},
|
||||
|
||||
maxTime: function(){
|
||||
var lastPost = _.last(this.photos.models);
|
||||
return lastPost[this.sortOrder()]()
|
||||
},
|
||||
|
||||
sortOrder : function() {
|
||||
return "createdAt";
|
||||
},
|
||||
|
||||
add : function(models){
|
||||
this.photos.add(models)
|
||||
}
|
||||
|
||||
});
|
||||
@@ -1,108 +0,0 @@
|
||||
app.models.Post = Backbone.Model.extend({
|
||||
urlRoot : "/posts",
|
||||
|
||||
initialize : function() {
|
||||
this.setupCollections();
|
||||
this.bind("change", this.setupCollections, this)
|
||||
},
|
||||
|
||||
setupCollections: function() {
|
||||
this.comments = new app.collections.Comments(this.get("comments") || this.get("last_three_comments"), {post : this});
|
||||
this.likes = this.likes || new app.collections.Likes([], {post : this}); // load in the user like initially
|
||||
this.participations = this.participations || new app.collections.Participations([], {post : this}); // load in the user like initially
|
||||
},
|
||||
|
||||
createdAt : function() {
|
||||
return this.timeOf("created_at");
|
||||
},
|
||||
|
||||
interactedAt : function() {
|
||||
return this.timeOf("interacted_at");
|
||||
},
|
||||
|
||||
timeOf: function(field) {
|
||||
return app.helpers.dateFormatter.parse(this.get(field)) / 1000;
|
||||
},
|
||||
|
||||
createReshareUrl : "/reshares",
|
||||
|
||||
reshare : function(){
|
||||
return this._reshare = this._reshare || new app.models.Reshare({root_guid : this.get("guid")});
|
||||
},
|
||||
|
||||
reshareAuthor : function(){
|
||||
return this.get("author")
|
||||
},
|
||||
|
||||
toggleFollow : function() {
|
||||
var userParticipation = this.get("user_participation");
|
||||
if(userParticipation) {
|
||||
this.unfollow();
|
||||
} else {
|
||||
this.follow();
|
||||
}
|
||||
},
|
||||
|
||||
follow : function() {
|
||||
var self = this;
|
||||
this.participations.create({}, {success : function(resp){
|
||||
self.set(resp)
|
||||
self.trigger('interacted', self)
|
||||
}});
|
||||
},
|
||||
|
||||
unfollow : function() {
|
||||
var self = this;
|
||||
var participationModel = new app.models.Participation(this.get("user_participation"));
|
||||
participationModel.url = this.participations.url + "/" + participationModel.id;
|
||||
|
||||
participationModel.destroy({success : function(model, resp){
|
||||
self.set(resp);
|
||||
self.trigger('interacted', this)
|
||||
}});
|
||||
},
|
||||
|
||||
toggleLike : function() {
|
||||
var userLike = this.get("user_like")
|
||||
if(userLike) {
|
||||
this.unlike()
|
||||
} else {
|
||||
this.like()
|
||||
}
|
||||
},
|
||||
|
||||
like : function() {
|
||||
var self = this;
|
||||
this.likes.create({}, {success : function(resp){
|
||||
self.set(resp)
|
||||
self.trigger('interacted', self)
|
||||
}});
|
||||
|
||||
},
|
||||
|
||||
unlike : function() {
|
||||
var self = this;
|
||||
var likeModel = new app.models.Like(this.get("user_like"));
|
||||
likeModel.url = this.likes.url + "/" + likeModel.id;
|
||||
|
||||
likeModel.destroy({success : function(model, resp) {
|
||||
self.set(resp);
|
||||
self.trigger('interacted', this)
|
||||
}});
|
||||
}
|
||||
}, {
|
||||
|
||||
frameMoods : [
|
||||
"Day"
|
||||
],
|
||||
|
||||
legacyTemplateNames : [
|
||||
"status-with-photo-backdrop",
|
||||
"note",
|
||||
"rich-media",
|
||||
"multi-photo",
|
||||
"photo-backdrop",
|
||||
"activity-streams-photo",
|
||||
"status"
|
||||
]
|
||||
});
|
||||
@@ -1,14 +0,0 @@
|
||||
app.models.Reshare = app.models.Post.extend({
|
||||
rootPost : function(){
|
||||
this._rootPost = this._rootPost || new app.models.Post(this.get("root"));
|
||||
return this._rootPost
|
||||
},
|
||||
|
||||
reshare : function(){
|
||||
return this.rootPost().reshare()
|
||||
},
|
||||
|
||||
reshareAuthor : function(){
|
||||
return this.rootPost().reshareAuthor()
|
||||
}
|
||||
});
|
||||
@@ -1,24 +0,0 @@
|
||||
app.models.StatusMessage = app.models.Post.extend({
|
||||
url : function(){
|
||||
return this.isNew() ? '/status_messages' : '/posts/' + this.get("id");
|
||||
},
|
||||
|
||||
defaults : {
|
||||
'post_type' : 'StatusMessage',
|
||||
'author' : app.currentUser ? app.currentUser.attributes : {}
|
||||
},
|
||||
|
||||
toJSON : function(){
|
||||
return {
|
||||
status_message : _.clone(this.attributes),
|
||||
aspect_ids : this.get("aspect_ids") && this.get("aspect_ids").split(","),
|
||||
photos : this.photos && this.photos.pluck("id"),
|
||||
services : mungeServices(this.get("services"))
|
||||
}
|
||||
|
||||
function mungeServices (values) {
|
||||
if(!values) { return; }
|
||||
return values.length > 1 ? values : [values]
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,67 +0,0 @@
|
||||
app.models.Stream = Backbone.Collection.extend({
|
||||
initialize : function(){
|
||||
this.posts = new app.collections.Posts([], this.postOptions());
|
||||
},
|
||||
|
||||
postOptions :function(){
|
||||
var order = this.sortOrder();
|
||||
return {
|
||||
comparator : function(post) { return -post[order](); }
|
||||
}
|
||||
},
|
||||
|
||||
url : function(){
|
||||
return _.any(this.posts.models) ? this.timeFilteredPath() : this.basePath()
|
||||
},
|
||||
|
||||
_fetching : false,
|
||||
|
||||
fetch: function() {
|
||||
if(this._fetching) { return false; }
|
||||
var self = this
|
||||
|
||||
// we're fetching the collection... there is probably a better way to do this
|
||||
self._fetching = true;
|
||||
|
||||
this.posts
|
||||
.fetch({
|
||||
add : true,
|
||||
url : self.url()
|
||||
})
|
||||
.done(
|
||||
function(resp){
|
||||
// we're done fetching... there is probably a better way to handle this
|
||||
self._fetching = false;
|
||||
|
||||
self.trigger("fetched", self);
|
||||
|
||||
// all loaded?
|
||||
if(resp.posts && (resp.posts.author || resp.posts.length == 0)) {
|
||||
self.trigger("allPostsLoaded", self);
|
||||
}
|
||||
}
|
||||
)
|
||||
return this;
|
||||
},
|
||||
|
||||
basePath : function(){
|
||||
return document.location.pathname;
|
||||
},
|
||||
|
||||
timeFilteredPath : function(){
|
||||
return this.basePath() + "?max_time=" + this.maxTime();
|
||||
},
|
||||
|
||||
maxTime: function(){
|
||||
var lastPost = _.last(this.posts.models);
|
||||
return lastPost[this.sortOrder()]()
|
||||
},
|
||||
|
||||
sortOrder : function() {
|
||||
return this.basePath().match(/activity/) ? "interactedAt" : "createdAt"
|
||||
},
|
||||
|
||||
add : function(models){
|
||||
this.posts.add(models)
|
||||
}
|
||||
});
|
||||
@@ -1,11 +0,0 @@
|
||||
app.models.User = Backbone.Model.extend({
|
||||
toggleNsfwState : function() {
|
||||
if(!app.currentUser.authenticated()){ return false }
|
||||
this.set({showNsfw : !this.get("showNsfw")});
|
||||
this.trigger("nsfwChanged");
|
||||
},
|
||||
|
||||
authenticated : function() {
|
||||
return !!this.id;
|
||||
}
|
||||
});
|
||||
@@ -1,97 +0,0 @@
|
||||
app.pages.PostViewer = app.views.Base.extend({
|
||||
|
||||
templateName: "post-viewer",
|
||||
|
||||
subviews : {
|
||||
"#post-content" : "postView",
|
||||
"#post-nav" : "navView",
|
||||
"#post-interactions" : "interactionsView",
|
||||
"#header-container" : "authorView"
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
this.model = new app.models.Post({ id : options.id });
|
||||
this.model.fetch().success(_.bind(this.initViews, this));
|
||||
|
||||
this.prepIdleHooks();
|
||||
|
||||
$(document).bind("keypress", _.bind(this.commentAnywhere, this))
|
||||
$(document).bind("keypress", _.bind(this.invokePane, this))
|
||||
$(document).bind("keyup", _.bind(this.closePane, this))
|
||||
},
|
||||
|
||||
initViews : function() {
|
||||
/* init view */
|
||||
this.authorView = new app.views.PostViewerAuthor({ model : this.model });
|
||||
this.interactionsView = new app.views.PostViewerInteractions({ model : this.model });
|
||||
this.navView = new app.views.PostViewerNav({ model : this.model });
|
||||
this.postView = app.views.Post.showFactory(this.model)
|
||||
|
||||
this.render();
|
||||
},
|
||||
|
||||
prepIdleHooks : function () {
|
||||
$.idleTimer(3000);
|
||||
|
||||
$(document).bind("idle.idleTimer", function(){
|
||||
$("body").addClass('idle');
|
||||
});
|
||||
|
||||
$(document).bind("active.idleTimer", function(){
|
||||
$("body").removeClass('idle');
|
||||
});
|
||||
},
|
||||
|
||||
postRenderTemplate : function() {
|
||||
/* set the document title */
|
||||
console.log(this.model)
|
||||
document.title = this.model.get("title");
|
||||
|
||||
this.bindNavHooks();
|
||||
},
|
||||
|
||||
bindNavHooks : function() {
|
||||
/* navagation hooks */
|
||||
var nextPostLocation = this.model.get("next_post");
|
||||
var previousPostLocation = this.model.get("previous_post");
|
||||
|
||||
|
||||
$(document).keydown(function(evt){
|
||||
/* prevent nav from happening if the user is using the arrow
|
||||
* keys to navigate through their comment text */
|
||||
if($(evt.target).is("textarea")) { return }
|
||||
|
||||
switch(evt.keyCode) {
|
||||
case 37:
|
||||
navigate(nextPostLocation); break;
|
||||
case 39:
|
||||
navigate(previousPostLocation); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
})
|
||||
|
||||
function navigate(loc) {
|
||||
loc ? window.location = loc : null
|
||||
}
|
||||
},
|
||||
|
||||
commentAnywhere : function(evt) {
|
||||
/* ignore enter, space bar, arrow keys */
|
||||
if(_.include([13, 32, 37, 38, 39, 40], evt.keyCode)) { return }
|
||||
|
||||
this.interactionsView.invokePane();
|
||||
$('#new-post-comment textarea').focus();
|
||||
},
|
||||
|
||||
invokePane : function(evt) {
|
||||
if(evt.keyCode != 32) { return }
|
||||
this.interactionsView.invokePane();
|
||||
},
|
||||
|
||||
closePane : function(evt) {
|
||||
if(evt.keyCode != 27) { return }
|
||||
this.interactionsView.hidePane();
|
||||
}
|
||||
|
||||
});
|
||||
@@ -1,57 +0,0 @@
|
||||
app.Router = Backbone.Router.extend({
|
||||
routes: {
|
||||
"activity": "stream",
|
||||
"stream": "stream",
|
||||
|
||||
"participate": "stream",
|
||||
"explore": "stream",
|
||||
|
||||
"aspects:query": "stream",
|
||||
"commented": "stream",
|
||||
"liked": "stream",
|
||||
"mentions": "stream",
|
||||
"people/:id": "stream",
|
||||
"people/:id/photos": "photos",
|
||||
"u/:name": "stream",
|
||||
"followed_tags": "stream",
|
||||
"tags/:name": "stream",
|
||||
|
||||
"posts/new" : "newPost",
|
||||
"posts/:id": "singlePost",
|
||||
"p/:id": "singlePost",
|
||||
"framer": "framer"
|
||||
},
|
||||
|
||||
stream : function() {
|
||||
app.stream = new app.models.Stream();
|
||||
app.page = new app.views.Stream({model : app.stream});
|
||||
app.publisher = app.publisher || new app.views.Publisher({collection : app.stream.posts});
|
||||
|
||||
var streamFacesView = new app.views.StreamFaces({collection : app.stream.posts});
|
||||
|
||||
$("#main_stream").html(app.page.render().el);
|
||||
$('#selected_aspect_contacts .content').html(streamFacesView.render().el);
|
||||
},
|
||||
|
||||
photos : function() {
|
||||
app.photos = new app.models.Photos();
|
||||
app.page = new app.views.Photos({model : app.photos});
|
||||
$("#main_stream").html(app.page.render().el);
|
||||
},
|
||||
|
||||
newPost : function(){
|
||||
var page = new app.pages.PostNew();
|
||||
$("#container").html(page.render().el)
|
||||
},
|
||||
|
||||
framer : function(){
|
||||
var page = new app.pages.Framer();
|
||||
$("#container").html(page.render().el)
|
||||
},
|
||||
|
||||
singlePost : function(id) {
|
||||
var page = new app.pages.PostViewer({ id: id });
|
||||
$("#container").html(page.el);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<a href="{{object_url}}" class="stream-photo-link">
|
||||
<img src="{{image_url}}" data-small-photo="{{image_url}}" data-full-photo="{{image_url}}" class="stream-photo" />
|
||||
</a>
|
||||
@@ -1,30 +0,0 @@
|
||||
{{#unless all_comments_loaded}}
|
||||
<div class="show_comments comment {{#unless showExpandCommentsLink}} hidden {{/unless}}">
|
||||
<div class="media">
|
||||
<a href="/posts/{{id}}/comments" class="toggle_post_comments">
|
||||
{{t "stream.more_comments" count=moreCommentsCount}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{{/unless}}
|
||||
|
||||
<div class="comments"> </div>
|
||||
|
||||
{{#if loggedIn}}
|
||||
<div class="comment no-border media new_comment_form_wrapper {{#unless comments_count}} hidden {{/unless}}">
|
||||
{{#with current_user}}
|
||||
<a href="/people/{{guid}}" class="img">
|
||||
{{{personImage this}}}
|
||||
</a>
|
||||
{{/with}}
|
||||
|
||||
<div class="bd">
|
||||
<form accept-charset="UTF-8" action="/posts/{{id}}/comments" class="new_comment" id="new_comment_on_{{id}}" method="post">
|
||||
<textarea class="comment_box" id="comment_text_on_{{id}}" name="text" rows="2" placeholder="{{t "stream.comment"}}" />
|
||||
<div class="submit_button">
|
||||
<input class="button creation" id="comment_submit_{{id}}" name="commit" type="submit" value="{{t "stream.comment"}}" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -1,27 +0,0 @@
|
||||
{{#if canRemove}}
|
||||
<div class="controls">
|
||||
<a href="#" class="delete comment_delete" title="{{t "delete"}}">
|
||||
<img alt="Deletelabel" src="{{imageUrl "deletelabel.png"}}" />
|
||||
<a/>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="img">
|
||||
{{#linkToPerson author}}
|
||||
{{{personImage this "small" "small"}}}
|
||||
{{/linkToPerson}}
|
||||
</div>
|
||||
|
||||
<div class="bd">
|
||||
<a href="/people/{{author.guid}}" class="author author-name">
|
||||
{{author.name}}
|
||||
</a>
|
||||
|
||||
<div class="collapsible comment-content">
|
||||
{{{text}}}
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
<time class="timeago" datetime="{{created_at}}"/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,43 +0,0 @@
|
||||
<span class="post_scope grey">
|
||||
{{#if public}}
|
||||
{{t "stream.public"}}
|
||||
{{else}}
|
||||
{{t "stream.limited"}}
|
||||
{{/if}}
|
||||
|
||||
{{#if provider_display_name}}
|
||||
<strong>
|
||||
via {{provider_display_name}}
|
||||
</strong>
|
||||
{{/if}}
|
||||
–
|
||||
</span>
|
||||
|
||||
<a href="#" class="participate_action" rel='nofollow'>
|
||||
{{#if user_participation}}
|
||||
{{t "stream.unfollow"}}
|
||||
{{else}}
|
||||
{{t "stream.follow"}}
|
||||
{{/if}}
|
||||
</a>
|
||||
·
|
||||
|
||||
<a href="#" class="like_action" rel='nofollow'>
|
||||
{{#if user_like}}
|
||||
{{t "stream.unlike"}}
|
||||
{{else}}
|
||||
{{t "stream.like"}}
|
||||
{{/if}}
|
||||
</a>
|
||||
·
|
||||
|
||||
{{#if userCanReshare}}
|
||||
<a href="#" class="reshare_action" rel='nofollow'>
|
||||
{{t "stream.reshare"}}
|
||||
</a>
|
||||
·
|
||||
{{/if}}
|
||||
|
||||
<a href="#" class="focus_comment_textarea" rel="nofollow">
|
||||
{{t "stream.comment"}}
|
||||
</a>
|
||||
@@ -1,117 +0,0 @@
|
||||
<div class="container" style="position:relative;">
|
||||
|
||||
<a href="/stream">
|
||||
<img alt="Logo_small" class="diaspora_header_logo" height="38px" width="65px" src="{{imageUrl "header-logo.png"}}" />
|
||||
</a>
|
||||
|
||||
<span class="header-nav">
|
||||
<span>
|
||||
<a href="/stream">
|
||||
{{t "my_stream"}}
|
||||
</a>
|
||||
</span>
|
||||
|
||||
<span>
|
||||
<a href="/activity">
|
||||
{{t "my_activity"}}
|
||||
</a>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<div id="nav_badges">
|
||||
<div class="badge" id="notification_badge">
|
||||
<a href="/notifications" title="{{t "header.notifications"}}">
|
||||
<img alt="{{t "header.notifications"}}" id="notification-flag" src="{{imageUrl "icons/notifications_grey.png"}}" />
|
||||
<div class="badge_count {{#unless current_user.notifications_count}} hidden {{/unless}}">
|
||||
{{current_user.notifications_count}}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="badge" id="message_inbox_badge">
|
||||
<a href="/conversations" title="{{t "header.messages"}}">
|
||||
<img alt="{{t "header.messages"}}" src="{{imageUrl "icons/mail_grey.png"}}" />
|
||||
<div class="badge_count {{#unless current_user.unread_messages_count}} hidden {{/unless}}">
|
||||
{{current_user.unread_messages_count}}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="notification_dropdown">
|
||||
<div class="header">
|
||||
<div class="right">
|
||||
<a href="#" id="mark_all_read_link">
|
||||
{{t "header.mark_all_as_read"}}
|
||||
</a>
|
||||
|
|
||||
<a href="/notifications" id="view_all_notifications">
|
||||
{{t "header.view_all"}}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<h4>
|
||||
{{t "header.recent_notifications"}}
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<div class="notifications">
|
||||
<div class="ajax_loader">
|
||||
<img alt="Ajax-loader" src="{{imageUrl "ajax-loader.gif"}}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="hovercard_container">
|
||||
<div id="hovercard">
|
||||
<img class="avatar">
|
||||
<h4>
|
||||
<a class="person"></a>
|
||||
</h4>
|
||||
<p class="handle"></p>
|
||||
<div id="hovercard_dropdown_container"></div>
|
||||
<div class="hovercard_footer">
|
||||
<div class="footer_container">
|
||||
<div class="hashtags"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="dropdown" id="user_menu">
|
||||
<li>
|
||||
<div class="right">
|
||||
▼
|
||||
</div>
|
||||
<img alt="{{current_user.name}}" class="avatar" src="{{current_user.avatar.small}}" title="{{current_user.name}}" />
|
||||
<a href="#">{{current_user.name}}</a>
|
||||
</li>
|
||||
<li><a href="/people/{{current_user.guid}}">{{t "header.profile"}}</a></li>
|
||||
<li><a href="/contacts">{{t "header.contacts"}}</a></li>
|
||||
<li><a href="/user/edit">{{t "header.settings"}}</a></li>
|
||||
{{#if current_user.admin}}
|
||||
<li><a href="/admins/user_search">{{t "header.admin"}}</a></li>
|
||||
{{/if}}
|
||||
<li><a href="/users/sign_out">{{t "header.log_out"}}</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<div id="global_search">
|
||||
<form accept-charset="UTF-8" action="/people" class="search_form" method="get">
|
||||
<input name="utf8" type="hidden" value="✓">
|
||||
<input id="q" name="q" placeholder="{{t "header.search"}}" results="5" type="search" autocomplete="off" class="ac_input">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="lightbox">
|
||||
<div id="lightbox-content">
|
||||
<a href="#" id="lightbox-close-link">[x] close</a>
|
||||
<img id="lightbox-image">
|
||||
<div id="lightbox-imageset"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="lightbox-backdrop"></div>
|
||||
|
||||
</div>
|
||||
@@ -1,28 +0,0 @@
|
||||
{{#if likes_count}}
|
||||
<div class="comment">
|
||||
<div class="media">
|
||||
<span class="img">
|
||||
<img alt="Heart" src="{{imageUrl "heart.png"}}" />
|
||||
</span>
|
||||
|
||||
<div class="bd">
|
||||
{{#unless likes.length}}
|
||||
<a href="#" class="expand_likes grey">
|
||||
{{t "stream.likes" count=likes_count}}
|
||||
</a>
|
||||
|
||||
{{else}}
|
||||
|
||||
{{#each likes}}
|
||||
{{#with attributes.author}}
|
||||
<a href="/people/{{guid}}">
|
||||
<img src="{{avatar.small}}" class="avatar micro" title="{{name}}"/>
|
||||
</a>
|
||||
{{/with}}
|
||||
{{/each}}
|
||||
|
||||
{{/unless}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -1,3 +0,0 @@
|
||||
<a href="#" class="photo-link">
|
||||
<img src="{{sizes.large}}" class="photo big_photo" data-small-photo="{{sizes.small}}" data-full-photo="{{sizes.large}}" rel="lightbox">
|
||||
</a>
|
||||
@@ -1,10 +0,0 @@
|
||||
<!-- header to be extracted -->
|
||||
|
||||
<div class="header">
|
||||
<div id="header-container"> </div>
|
||||
</div>
|
||||
|
||||
<div id="post-content"> </div>
|
||||
<div id="post-nav"> </div>
|
||||
<div id="post-interactions"> </div>
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
<div class="img">
|
||||
{{#linkToPerson author}}
|
||||
{{{personImage this "small"}}}
|
||||
{{/linkToPerson}}
|
||||
</div>
|
||||
|
||||
<div class="bd">
|
||||
{{#linkToPerson author}}
|
||||
{{name}}
|
||||
{{/linkToPerson}}
|
||||
|
||||
{{#if root}}
|
||||
<i class="icon-retweet"></i>
|
||||
{{#linkToPerson root.author}}
|
||||
{{name}}
|
||||
{{/linkToPerson}}
|
||||
{{/if}}
|
||||
|
||||
<div class="post-time">
|
||||
<time datetime="{{created_at}}" />
|
||||
{{#unless public}}
|
||||
<i class="icon-lock"> </i>
|
||||
{{/unless}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,15 +0,0 @@
|
||||
<div class="img">
|
||||
{{#linkToPerson author}}
|
||||
{{{personImage this "small" "small"}}}
|
||||
{{/linkToPerson}}
|
||||
</div>
|
||||
|
||||
<div class="bd">
|
||||
{{#linkToPerson author}}
|
||||
{{name}}
|
||||
{{/linkToPerson}}
|
||||
|
||||
<div class="comment-content">
|
||||
{{{text}}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,7 +0,0 @@
|
||||
<div class="photoset">
|
||||
<div class="img-bounding-box">
|
||||
<a href="{{object_url}}" class="stream-photo-link">
|
||||
<img src="{{image_url}}" data-small-photo="{{image_url}}" data-full-photo="{{image_url}}" class="stream-photo" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,9 +0,0 @@
|
||||
{{{text}}}
|
||||
|
||||
<div class="photoset">
|
||||
{{#each photos}}
|
||||
<div class="img-bounding-box">
|
||||
<img src="{{sizes.large}}" />
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
@@ -1,3 +0,0 @@
|
||||
<div class="note-content">
|
||||
{{{text}}}
|
||||
</div>
|
||||
@@ -1,4 +0,0 @@
|
||||
{{#each photos}}
|
||||
<div class="photo-fill" style="background-image: url({{sizes.large}})"> </div>
|
||||
<img src="{{sizes.large}}" />
|
||||
{{/each}}
|
||||
@@ -1,11 +0,0 @@
|
||||
<div class="rich-media-container">
|
||||
<div class="rich-media-container2">
|
||||
|
||||
{{{o_embed_cache.data.html}}}
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
{{{text}}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,9 +0,0 @@
|
||||
{{#each photos}}
|
||||
<div class="photo-fill" style="background-image: url({{sizes.large}})">
|
||||
<div class="darken">
|
||||
<div class="darken-content">
|
||||
{{{../text}}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
@@ -1 +0,0 @@
|
||||
{{{text}}}
|
||||
@@ -1,66 +0,0 @@
|
||||
<a href="#" rel="auth-required" class="label like" title="{{#if user_like}} {{t "viewer.unlike"}} {{else}} {{t "viewer.like"}} {{/if}}">
|
||||
{{#if user_like}}
|
||||
<i class="icon-heart icon-red"></i>
|
||||
{{else}}
|
||||
<i class="icon-heart icon-white"></i>
|
||||
{{/if}}
|
||||
{{likes_count}}
|
||||
</a>
|
||||
|
||||
<a href="#" rel="auth-required" class="label follow" title="{{#if user_participation}} {{t "viewer.stop_following_post"}} {{else}} {{t "viewer.follow_post"}} {{/if}}">
|
||||
{{#if user_participation}}
|
||||
<i class="icon-plus icon-green"></i>
|
||||
{{else}}
|
||||
<i class="icon-plus icon-white"></i>
|
||||
{{/if}}
|
||||
{{participations_count}}
|
||||
</a>
|
||||
|
||||
{{#if userCanReshare}}
|
||||
<a href="#" rel="auth-required" class="label reshare" title="{{#if user_reshare}} {{t "viewer.reshared"}} {{else}} {{t "viewer.reshare"}} {{/if}}">
|
||||
{{#if user_reshare}}
|
||||
<i class="icon-retweet icon-blue"></i>
|
||||
{{else}}
|
||||
<i class="icon-retweet icon-white"></i>
|
||||
{{/if}}
|
||||
{{reshares_count}}
|
||||
</a>
|
||||
{{else}}
|
||||
<a class="label reshare-viewonly" title="{{#if user_reshare}} {{t "viewer.reshared"}} {{else}} {{t "viewer.reshare"}} {{/if}}">
|
||||
{{#if user_reshare}}
|
||||
<i class="icon-retweet icon-blue"></i>
|
||||
{{else}}
|
||||
<i class="icon-retweet icon-white"></i>
|
||||
{{/if}}
|
||||
{{reshares_count}}
|
||||
</a>
|
||||
{{/if}}
|
||||
|
||||
<a href="#" class="label comment" rel="invoke-interaction-pane" title="{{t "viewer.comment"}}">
|
||||
<i class="icon-comment icon-white"></i>
|
||||
{{comments_count}}
|
||||
</a>
|
||||
|
||||
<!-- this acts as a dock underlay -->
|
||||
<div id="post-info-sneaky" class="passive">
|
||||
<div id="post-info-container-sneaky">
|
||||
<a href="#" rel="invoke-interaction-pane" class="invoker">
|
||||
<img src="/images/up-tick-inset.png" class="info-tick"/>
|
||||
<a href="/" title="{{t "header.home"}}" class="home-button">
|
||||
<i class="icon-home icon-white"></i>
|
||||
</a>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- this closes an open interaction pane -->
|
||||
<div id="close-reactions-pane">
|
||||
<div id="close-reactions-pane-container">
|
||||
<a href="#" rel="hide-interaction-pane" class="invoker">
|
||||
<a href="/" title="{{t "header.home"}}" class="home-button">
|
||||
<i class="icon-home icon-white"></i>
|
||||
</a>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
<div id="post-feedback"> </div>
|
||||
|
||||
<div id="post-info" style="display:none;">
|
||||
<div id="post-info-container">
|
||||
<img src="/images/down-tick-inset.png" class="info-tick"/>
|
||||
|
||||
<div id="post-reactions"> </div>
|
||||
<div id="new-post-comment"> </div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
<a href="#" class="nav-arrow left" id="forward">
|
||||
<div class="nav-arrow-inner">
|
||||
<img src="/images/arrow-left.png" />
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="#" class="nav-arrow right" id="back">
|
||||
<div class="nav-arrow-inner">
|
||||
<img src="/images/arrow-right.png" />
|
||||
</div>
|
||||
</a>
|
||||
@@ -1,8 +0,0 @@
|
||||
<div id="new-post-comment-container">
|
||||
<form class="form-inline">
|
||||
<textarea class="new-comment-text" id="new-comment-text" placeholder="{{t "stream.comment"}}"></textarea>
|
||||
<button type="submit" class="btn btn-small">
|
||||
{{t "stream.comment"}}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -1,53 +0,0 @@
|
||||
{{# if likes}}
|
||||
<div id="post-likes">
|
||||
<div class="well media">
|
||||
<div class="img">
|
||||
<i class="icon-heart icon-red"></i>
|
||||
</div>
|
||||
<div class="bd">
|
||||
{{#each likes}}
|
||||
{{#linkToPerson author}}
|
||||
{{{personImage this "small" "micro"}}}
|
||||
{{/linkToPerson}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{# if participations}}
|
||||
<div id="post-follows">
|
||||
<div class="well media">
|
||||
<div class="img">
|
||||
<i class="icon-plus icon-green"></i>
|
||||
</div>
|
||||
<div class="bd">
|
||||
{{#each participations}}
|
||||
{{#linkToPerson author}}
|
||||
{{{personImage this "small" "micro"}}}
|
||||
{{/linkToPerson}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{# if reshares}}
|
||||
<div id="post-reshares">
|
||||
<div class="well media">
|
||||
<div class="img">
|
||||
<i class="icon-retweet icon-blue"></i>
|
||||
</div>
|
||||
<div class="bd">
|
||||
{{#each reshares}}
|
||||
{{#linkToPerson author}}
|
||||
{{{personImage this "small" "micro"}}}
|
||||
{{/linkToPerson}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div id="post-comments"> </div>
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
<div class="reshare">
|
||||
|
||||
{{#if root}}
|
||||
|
||||
<div class="media">
|
||||
|
||||
{{#with root}}
|
||||
<a href="/people/{{author.guid}}" class="img">
|
||||
<img src="{{author.avatar.small}}" class="avatar" />
|
||||
</a>
|
||||
{{/with}}
|
||||
|
||||
{{#with root}}
|
||||
<div class="bd">
|
||||
<div>
|
||||
<a href="/people/{{author.guid}}" class="author">
|
||||
{{author.name}}
|
||||
</a>
|
||||
|
||||
<span class="details grey">
|
||||
-
|
||||
<a href="/posts/{{id}}">
|
||||
<time class="timeago" datetime="{{created_at}}"/>
|
||||
</a>
|
||||
|
||||
{{#if reshares_count}}
|
||||
-
|
||||
{{t "stream.reshares" count=reshares_count}}
|
||||
{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
{{/with}}
|
||||
|
||||
{{> status-message}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{else}}
|
||||
|
||||
<p>
|
||||
{{t "stream.original_post_deleted"}}
|
||||
</p>
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
@@ -1 +0,0 @@
|
||||
<span class=text>{{ text }}</span>
|
||||
@@ -1,31 +0,0 @@
|
||||
{{#if largePhoto}}
|
||||
<div class="photo_attachments">
|
||||
|
||||
<a href="#" class="stream-photo-link">
|
||||
{{#with largePhoto}}
|
||||
<img src="{{sizes.large}}" class="stream-photo big_stream_photo" data-small-photo="{{sizes.small}}" data-full-photo="{{sizes.large}}" rel="lightbox">
|
||||
{{/with}}
|
||||
</a>
|
||||
|
||||
{{#each smallPhotos}}
|
||||
<a href="#" class="stream-photo-link">
|
||||
<img src="{{sizes.small}}" class="stream-photo thumb_small" data-small-photo="{{sizes.small}}" data-full-photo="{{sizes.large}}" rel="lightbox">
|
||||
</a>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
<div class="collapsible">
|
||||
{{{text}}}
|
||||
{{#if o_embed_cache}}
|
||||
<div class="oembed">
|
||||
{{#if o_embed_cache.data.thumbnail_url}}
|
||||
<div class="thumb">
|
||||
<img src="{{o_embed_cache.data.thumbnail_url}}" />
|
||||
<div class="video-overlay"></div>
|
||||
</div>
|
||||
{{else}}
|
||||
{{{o_embed_html}}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
@@ -1,80 +0,0 @@
|
||||
<div class="media">
|
||||
|
||||
{{#if current_user}}
|
||||
<div class="controls">
|
||||
{{#unless authorIsCurrentUser}}
|
||||
<a href="#" rel=nofollow>
|
||||
<img src="{{imageUrl "ignoreuser.png"}}"" alt="Ignoreuser" class="block_user control_icon" title="{{t "ignore"}}" />
|
||||
</a>
|
||||
<a href="#" rel=nofollow>
|
||||
<img src="{{imageUrl "deletelabel.png"}}" class="delete control_icon hide_post" title="{{t "stream.hide"}}" />
|
||||
</a>
|
||||
{{else}}
|
||||
<a href="#" rel=nofollow>
|
||||
<img src="{{imageUrl "deletelabel.png"}}" class="delete control_icon remove_post" title="{{t "delete"}}" />
|
||||
</a>
|
||||
{{/unless}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#with author}}
|
||||
<a href="/people/{{guid}}" class="img">
|
||||
{{{personImage this}}}
|
||||
</a>
|
||||
{{/with}}
|
||||
|
||||
<div class="bd">
|
||||
<div>
|
||||
{{#with author}}
|
||||
<a href="/people/{{guid}}" class="author">
|
||||
{{name}}
|
||||
</a>
|
||||
{{/with}}
|
||||
|
||||
<span class="details grey">
|
||||
-
|
||||
<a href="/posts/{{id}}">
|
||||
<time class="timeago" datetime="{{created_at}}" />
|
||||
</a>
|
||||
|
||||
{{#if reshares_count}}
|
||||
-
|
||||
{{t "stream.reshares" count=reshares_count}}
|
||||
{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{{#if showPost}}
|
||||
{{#if nsfw}}
|
||||
<div class="nsfw_off">
|
||||
<strong>
|
||||
#NSFW
|
||||
</strong>
|
||||
|
|
||||
<a href="#" class="toggle_nsfw_state">
|
||||
{{t "stream.hide_nsfw_posts"}}
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="post-content"> </div>
|
||||
|
||||
<div class="feedback"> </div>
|
||||
<div class="likes"> </div>
|
||||
<div class="comments"> </div>
|
||||
{{else}}
|
||||
<div class="nsfw-shield">
|
||||
<strong>
|
||||
#NSFW
|
||||
</strong>
|
||||
|
|
||||
<a href="#" class="show_nsfw_post">
|
||||
{{t "stream.show_nsfw_post"}}
|
||||
</a>
|
||||
|
|
||||
<a href="#" class="toggle_nsfw_state">
|
||||
{{t "stream.show_nsfw_posts"}}
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
@@ -1,5 +0,0 @@
|
||||
{{#people}}
|
||||
{{#linkToPerson this}}
|
||||
{{{personImage this "small"}}}
|
||||
{{/linkToPerson}}
|
||||
{{/people}}
|
||||
@@ -1,70 +0,0 @@
|
||||
app.views.Base = Backbone.View.extend({
|
||||
|
||||
initialize : function(options) {
|
||||
this.setupRenderEvents();
|
||||
},
|
||||
|
||||
presenter : function(){
|
||||
return this.defaultPresenter()
|
||||
},
|
||||
|
||||
setupRenderEvents : function(){
|
||||
if(this.model) {
|
||||
//this should be in streamobjects view
|
||||
this.model.bind('remove', this.remove, this);
|
||||
}
|
||||
|
||||
// this line is too generic. we usually only want to re-render on
|
||||
// feedback changes as the post content, author, and time do not change.
|
||||
//
|
||||
// this.model.bind('change', this.render, this);
|
||||
},
|
||||
|
||||
defaultPresenter : function(){
|
||||
var modelJson = this.model ? _.clone(this.model.attributes) : {}
|
||||
return _.extend(modelJson, {
|
||||
current_user : app.currentUser.attributes,
|
||||
loggedIn : app.currentUser.authenticated()
|
||||
});
|
||||
},
|
||||
|
||||
render : function() {
|
||||
this.renderTemplate()
|
||||
this.renderSubviews()
|
||||
this.renderPluginWidgets()
|
||||
this.removeTooltips()
|
||||
|
||||
return this
|
||||
},
|
||||
|
||||
renderTemplate : function(){
|
||||
var presenter = _.isFunction(this.presenter) ? this.presenter() : this.presenter
|
||||
this.template = JST[this.templateName]
|
||||
$(this.el)
|
||||
.html(this.template(presenter))
|
||||
.attr("data-template", _.last(this.templateName.split("/")));
|
||||
this.postRenderTemplate();
|
||||
},
|
||||
|
||||
postRenderTemplate : $.noop, //hella callbax yo
|
||||
|
||||
renderSubviews : function(){
|
||||
var self = this;
|
||||
_.each(this.subviews, function(property, selector){
|
||||
var view = _.isFunction(self[property]) ? self[property]() : self[property]
|
||||
if(view) {
|
||||
self.$(selector).html(view.render().el)
|
||||
view.delegateEvents();
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
renderPluginWidgets : function() {
|
||||
this.$(this.tooltipSelector).twipsy();
|
||||
this.$("time").timeago();
|
||||
},
|
||||
|
||||
removeTooltips : function() {
|
||||
$(".twipsy").remove();
|
||||
}
|
||||
});
|
||||
@@ -1,79 +0,0 @@
|
||||
app.views.CommentStream = app.views.Base.extend({
|
||||
|
||||
templateName: "comment-stream",
|
||||
|
||||
className : "comment_stream",
|
||||
|
||||
events: {
|
||||
"submit form": "createComment",
|
||||
"focus .comment_box": "commentTextareaFocused",
|
||||
"click .toggle_post_comments": "expandComments"
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
this.commentTemplate = options.commentTemplate;
|
||||
|
||||
this.setupBindings();
|
||||
},
|
||||
|
||||
setupBindings: function() {
|
||||
this.model.comments.bind('add', this.appendComment, this);
|
||||
this.model.bind("commentsExpanded", this.render, this);
|
||||
},
|
||||
|
||||
postRenderTemplate : function() {
|
||||
this.$("textarea").placeholder();
|
||||
this.model.comments.each(this.appendComment, this);
|
||||
|
||||
// add autoexpanders to new comment textarea
|
||||
this.$("textarea").autoResize({'extraSpace' : 10});
|
||||
},
|
||||
|
||||
presenter: function(){
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
moreCommentsCount : (this.model.get("comments_count") - 3),
|
||||
showExpandCommentsLink : (this.model.get("comments_count") > 3)
|
||||
})
|
||||
},
|
||||
|
||||
createComment: function(evt) {
|
||||
if(evt){ evt.preventDefault(); }
|
||||
|
||||
this.model.comments.create({
|
||||
"text" : this.$(".comment_box").val()
|
||||
});
|
||||
|
||||
this.$(".comment_box").val("")
|
||||
return this;
|
||||
},
|
||||
|
||||
appendComment: function(comment) {
|
||||
// Set the post as the comment's parent, so we can check
|
||||
// on post ownership in the Comment view.
|
||||
comment.set({parent : this.model.toJSON()})
|
||||
|
||||
this.$(".comments").append(new app.views.Comment({
|
||||
model: comment
|
||||
}).render().el);
|
||||
},
|
||||
|
||||
commentTextareaFocused: function(evt){
|
||||
this.$("form").removeClass('hidden').addClass("open");
|
||||
},
|
||||
|
||||
expandComments: function(evt){
|
||||
if(evt){ evt.preventDefault(); }
|
||||
|
||||
var self = this;
|
||||
this.model.comments.fetch({
|
||||
success : function(resp){
|
||||
self.model.set({
|
||||
comments : resp.models,
|
||||
all_comments_loaded : true
|
||||
})
|
||||
self.model.trigger("commentsExpanded", self)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
@@ -1,31 +0,0 @@
|
||||
app.views.Comment = app.views.Content.extend({
|
||||
|
||||
templateName: "comment",
|
||||
|
||||
className : "comment media",
|
||||
|
||||
events : function() {
|
||||
return _.extend(app.views.Content.prototype.events, {
|
||||
"click .comment_delete": "destroyModel"
|
||||
});
|
||||
},
|
||||
|
||||
presenter : function() {
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
canRemove: this.canRemove(),
|
||||
text : app.helpers.textFormatter(this.model)
|
||||
})
|
||||
},
|
||||
|
||||
ownComment : function() {
|
||||
return app.currentUser.authenticated() && this.model.get("author").diaspora_id == app.currentUser.get("diaspora_id")
|
||||
},
|
||||
|
||||
postOwner : function() {
|
||||
return app.currentUser.authenticated() && this.model.get("parent").author.diaspora_id == app.currentUser.get("diaspora_id")
|
||||
},
|
||||
|
||||
canRemove : function() {
|
||||
return app.currentUser.authenticated() && (this.ownComment() || this.postOwner())
|
||||
}
|
||||
});
|
||||
@@ -1,69 +0,0 @@
|
||||
app.views.Content = app.views.StreamObject.extend({
|
||||
|
||||
events: {
|
||||
"click .oembed .thumb": "showOembedContent",
|
||||
"click .expander": "expandPost"
|
||||
},
|
||||
|
||||
presenter : function(){
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
text : app.helpers.textFormatter(this.model),
|
||||
o_embed_html : this.embedHTML(),
|
||||
largePhoto : this.largePhoto(),
|
||||
smallPhotos : this.smallPhotos()
|
||||
});
|
||||
},
|
||||
|
||||
embedHTML: function(){
|
||||
if(!this.model.get("o_embed_cache")) { return ""; }
|
||||
var data = this.model.get("o_embed_cache").data;
|
||||
if(data.type == "photo") {
|
||||
return '<img src="'+data.url+'" width="'+data.width+'" height="'+data.height+'" />';
|
||||
} else {
|
||||
return data.html || ""
|
||||
}
|
||||
},
|
||||
|
||||
largePhoto : function() {
|
||||
var photos = this.model.get("photos")
|
||||
if(!photos || photos.length == 0) { return }
|
||||
return photos[0]
|
||||
},
|
||||
|
||||
smallPhotos : function() {
|
||||
var photos = this.model.get("photos")
|
||||
if(!photos || photos.length < 2) { return }
|
||||
return photos.slice(1,8)
|
||||
},
|
||||
|
||||
showOembedContent: function() {
|
||||
var oembed = $(this.el).find(".oembed");
|
||||
var insertHTML = $( this.embedHTML() );
|
||||
var paramSeparator = ( /\?/.test(insertHTML.attr("src")) ) ? "&" : "?";
|
||||
insertHTML.attr("src", insertHTML.attr("src") + paramSeparator + "autoplay=1");
|
||||
oembed.html( insertHTML );
|
||||
},
|
||||
|
||||
expandPost: function(evt) {
|
||||
var el = $(this.el).find('.collapsible');
|
||||
el.removeClass('collapsed').addClass('opened');
|
||||
el.animate({'height':el.data('orig-height')}, 550, function() {
|
||||
el.css('height','auto');
|
||||
});
|
||||
$(evt.currentTarget).hide();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
app.views.StatusMessage = app.views.Content.extend({
|
||||
templateName : "status-message"
|
||||
});
|
||||
|
||||
app.views.Reshare = app.views.Content.extend({
|
||||
templateName : "reshare"
|
||||
});
|
||||
|
||||
app.views.ActivityStreams__Photo = app.views.Content.extend({
|
||||
templateName : "activity-streams-photo"
|
||||
});
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
app.views.Feedback = app.views.Base.extend({
|
||||
|
||||
templateName: "feedback",
|
||||
|
||||
className : "info",
|
||||
|
||||
events: {
|
||||
"click .like_action" : "toggleLike",
|
||||
"click .participate_action" : "toggleFollow",
|
||||
"click .reshare_action" : "resharePost"
|
||||
},
|
||||
|
||||
initialize : function() {
|
||||
this.model.bind('interacted', this.render, this);
|
||||
},
|
||||
|
||||
presenter : function() {
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
userCanReshare : this.userCanReshare()
|
||||
})
|
||||
},
|
||||
|
||||
toggleFollow : function(evt) {
|
||||
if(evt) { evt.preventDefault(); }
|
||||
this.model.toggleFollow();
|
||||
},
|
||||
|
||||
toggleLike: function(evt) {
|
||||
if(evt) { evt.preventDefault(); }
|
||||
this.model.toggleLike();
|
||||
},
|
||||
|
||||
resharePost : function(evt) {
|
||||
if(evt) { evt.preventDefault(); }
|
||||
if(!window.confirm("Reshare " + this.model.reshareAuthor().name + "'s post?")) { return }
|
||||
var reshare = this.model.reshare()
|
||||
var model = this.model
|
||||
|
||||
reshare.save({}, {
|
||||
url: this.model.createReshareUrl,
|
||||
success : function(resp){
|
||||
app.stream && app.stream.add(reshare);
|
||||
model.trigger("interacted")
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
userCanReshare : function() {
|
||||
var isReshare = this.model.get("post_type") == "Reshare"
|
||||
var rootExists = (isReshare ? this.model.get("root") : true)
|
||||
|
||||
var publicPost = this.model.get("public");
|
||||
var userIsNotAuthor = this.model.get("author").diaspora_id != app.currentUser.get("diaspora_id");
|
||||
var userIsNotRootAuthor = rootExists && (isReshare ? this.model.get("root").author.diaspora_id != app.currentUser.get("diaspora_id") : true)
|
||||
|
||||
return publicPost && app.currentUser.authenticated() && userIsNotAuthor && userIsNotRootAuthor;
|
||||
}
|
||||
});
|
||||
@@ -1,35 +0,0 @@
|
||||
app.views.Header = app.views.Base.extend({
|
||||
|
||||
templateName : "header",
|
||||
|
||||
className : "dark-header",
|
||||
|
||||
events : {
|
||||
"click ul.dropdown li:first-child" : "toggleDropdown"
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
$(document.body).click($.proxy(this.hideDropdown, this));
|
||||
return this;
|
||||
},
|
||||
|
||||
menuElement : function() {
|
||||
return this.$("ul.dropdown");
|
||||
},
|
||||
|
||||
toggleDropdown : function(evt) {
|
||||
if(evt){ evt.preventDefault(); }
|
||||
|
||||
this.menuElement().toggleClass("active");
|
||||
|
||||
if($.browser.msie) {
|
||||
this.$("header").toggleClass('ie-user-menu-active');
|
||||
}
|
||||
},
|
||||
|
||||
hideDropdown : function(evt) {
|
||||
if(this.menuElement().hasClass("active") && !$(evt.target).parents("#user_menu").length) {
|
||||
this.menuElement().removeClass("active");
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,31 +0,0 @@
|
||||
app.views.LikesInfo = app.views.StreamObject.extend({
|
||||
|
||||
templateName : "likes-info",
|
||||
|
||||
events : {
|
||||
"click .expand_likes" : "showAvatars"
|
||||
},
|
||||
|
||||
tooltipSelector : ".avatar",
|
||||
|
||||
initialize : function() {
|
||||
this.model.bind('expandedLikes', this.render, this)
|
||||
},
|
||||
|
||||
presenter : function() {
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
likes : this.model.likes.models
|
||||
})
|
||||
},
|
||||
|
||||
showAvatars : function(evt){
|
||||
if(evt) { evt.preventDefault() }
|
||||
var self = this;
|
||||
this.model.likes.fetch()
|
||||
.done(function(resp){
|
||||
// set like attribute and like collection
|
||||
self.model.set({likes : self.model.likes.reset(resp)})
|
||||
self.model.trigger("expandedLikes")
|
||||
})
|
||||
}
|
||||
});
|
||||
@@ -1,13 +0,0 @@
|
||||
app.views.Photo = app.views.StreamObject.extend({
|
||||
|
||||
templateName: "photo",
|
||||
|
||||
className : "photo loaded",
|
||||
|
||||
initialize : function() {
|
||||
$(this.el).attr("id", this.model.get("guid"));
|
||||
this.model.bind('remove', this.remove, this);
|
||||
return this;
|
||||
}
|
||||
|
||||
});
|
||||
@@ -1,60 +0,0 @@
|
||||
app.views.Photos = Backbone.View.extend({
|
||||
|
||||
events : {},
|
||||
|
||||
initialize : function(options) {
|
||||
this.photos = this.model;
|
||||
this.collection = this.model.photos;
|
||||
|
||||
this.setupEvents();
|
||||
this.setupLightbox();
|
||||
},
|
||||
|
||||
setupEvents : function(){
|
||||
this.photos.bind("fetched", this.removeLoader, this)
|
||||
this.collection.bind("add", this.addPhoto, this);
|
||||
},
|
||||
|
||||
addPhoto : function(photo) {
|
||||
var photoView = new app.views.Photo({ model: photo });
|
||||
|
||||
$(this.el)[
|
||||
(this.collection.at(0).id == photo.id)
|
||||
? "prepend"
|
||||
: "append"
|
||||
](photoView.render().el);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
render : function(evt) {
|
||||
if(evt) {evt.preventDefault(); }
|
||||
|
||||
if(this.model.fetch()) {
|
||||
this.appendLoader();
|
||||
};
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
appendLoader: function(){
|
||||
$("#paginate").html($("<img>", {
|
||||
src : "/images/static-loader.png",
|
||||
"class" : "loader"
|
||||
}));
|
||||
},
|
||||
|
||||
removeLoader: function() {
|
||||
$("#paginate").empty();
|
||||
},
|
||||
|
||||
setupLightbox : function(){
|
||||
this.lightbox = Diaspora.BaseWidget.instantiate("Lightbox");
|
||||
this.lightbox.set({
|
||||
imageParent: '#main_stream',
|
||||
imageSelector: 'img.photo'
|
||||
});
|
||||
$(this.el).delegate("a.photo-link", "click", this.lightbox.lightboxImageClicked);
|
||||
},
|
||||
|
||||
});
|
||||
@@ -1,8 +0,0 @@
|
||||
app.views.PostViewerAuthor = app.views.Base.extend({
|
||||
|
||||
id : "post-author",
|
||||
className : "media",
|
||||
|
||||
templateName: "post-viewer/author"
|
||||
|
||||
});
|
||||
@@ -1,40 +0,0 @@
|
||||
app.views.PostViewerFeedback = app.views.Feedback.extend({
|
||||
|
||||
id : "user-controls",
|
||||
className : "",
|
||||
|
||||
templateName: "post-viewer/feedback",
|
||||
|
||||
events : {
|
||||
"click *[rel='auth-required']" : "requireAuth",
|
||||
|
||||
"click .like" : "toggleLike",
|
||||
"click .follow" : "toggleFollow",
|
||||
"click .reshare" : "resharePost",
|
||||
|
||||
"click *[rel='invoke-interaction-pane']" : "invokePane",
|
||||
"click *[rel='hide-interaction-pane']" : "hidePane"
|
||||
},
|
||||
|
||||
tooltipSelector : ".label, .home-button",
|
||||
|
||||
postRenderTemplate : function() {
|
||||
this.sneakyVisiblity()
|
||||
},
|
||||
|
||||
sneakyVisiblity : function() {
|
||||
if(!$("#post-info").is(":visible")) {
|
||||
this.$("#post-info-sneaky").removeClass('passive')
|
||||
}
|
||||
},
|
||||
|
||||
invokePane : function(evt){ this.trigger("invokePane") },
|
||||
hidePane : function(evt){ this.trigger("hidePane") },
|
||||
|
||||
requireAuth : function(evt) {
|
||||
if( app.currentUser.authenticated() ) { return }
|
||||
alert("you must be logged in to do that!")
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
@@ -1,56 +0,0 @@
|
||||
app.views.PostViewerInteractions = app.views.Base.extend({
|
||||
|
||||
className : "",
|
||||
|
||||
subviews : {
|
||||
"#post-feedback" : "feedbackView",
|
||||
"#post-reactions" : "reactionsView",
|
||||
"#new-post-comment" : "newCommentView"
|
||||
},
|
||||
|
||||
templateName: "post-viewer/interactions",
|
||||
|
||||
initialize : function() {
|
||||
this.initViews();
|
||||
|
||||
this.feedbackView && this.feedbackView.bind("invokePane", this.invokePane, this)
|
||||
this.feedbackView && this.feedbackView.bind("hidePane", this.hidePane, this)
|
||||
},
|
||||
|
||||
initViews : function() {
|
||||
this.reactionsView = new app.views.PostViewerReactions({ model : this.model })
|
||||
|
||||
/* subviews that require user */
|
||||
this.feedbackView = new app.views.PostViewerFeedback({ model : this.model })
|
||||
if(app.currentUser.authenticated()) {
|
||||
this.newCommentView = new app.views.PostViewerNewComment({ model : this.model })
|
||||
}
|
||||
},
|
||||
|
||||
togglePane : function(evt) {
|
||||
if(evt) { evt.preventDefault() }
|
||||
$("#post-interactions").toggleClass("active")
|
||||
this.$("#post-info").slideToggle(300)
|
||||
this.removeTooltips()
|
||||
},
|
||||
|
||||
invokePane : function() {
|
||||
if(!this.$("#post-info").is(":visible")) {
|
||||
this.$("#post-info-sneaky").addClass("passive")
|
||||
this.togglePane()
|
||||
}
|
||||
},
|
||||
|
||||
hidePane : function() {
|
||||
if(this.$("#post-info").is(":visible")) {
|
||||
|
||||
/* it takes about 400ms for the pane to hide. we need to keep
|
||||
* the sneaky hidden until the slide is complete */
|
||||
setTimeout(function(){
|
||||
this.$("#post-info-sneaky").removeClass("passive")
|
||||
}, 400)
|
||||
|
||||
this.togglePane()
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,30 +0,0 @@
|
||||
app.views.PostViewerNav = app.views.Base.extend({
|
||||
|
||||
templateName: "post-viewer/nav",
|
||||
|
||||
events : {
|
||||
"click a" : "pjax"
|
||||
},
|
||||
|
||||
postRenderTemplate : function() {
|
||||
var mappings = {"#forward" : "next_post",
|
||||
"#back" : "previous_post"};
|
||||
|
||||
_.each(mappings, function(attribute, selector){
|
||||
this.setArrow(this.$(selector), this.model.get(attribute))
|
||||
}, this);
|
||||
},
|
||||
|
||||
setArrow : function(arrow, loc) {
|
||||
loc ? arrow.attr('href', loc) : arrow.remove()
|
||||
},
|
||||
|
||||
pjax : function(evt) {
|
||||
if(evt) { evt.preventDefault(); }
|
||||
var link;
|
||||
|
||||
evt.target.tagName != "A" ? link = $(evt.target).closest("a") : link = $(evt.target)
|
||||
app.router.navigate(link.attr("href").substring(1), true)
|
||||
}
|
||||
|
||||
});
|
||||
@@ -1,45 +0,0 @@
|
||||
app.views.PostViewerNewComment = app.views.Base.extend({
|
||||
|
||||
templateName: "post-viewer/new-comment",
|
||||
|
||||
events : {
|
||||
"click button" : "createComment",
|
||||
"focus textarea" : "scrollToBottom"
|
||||
},
|
||||
|
||||
scrollableArea : "#post-reactions",
|
||||
|
||||
postRenderTemplate : function() {
|
||||
this.$("textarea").placeholder();
|
||||
this.$("textarea").autoResize({'extraSpace' : 0});
|
||||
},
|
||||
|
||||
createComment: function(evt) {
|
||||
if(evt){ evt.preventDefault(); }
|
||||
|
||||
var self = this;
|
||||
|
||||
this.toggleFormState()
|
||||
this.model.comments.create({
|
||||
"text" : this.$("textarea").val()
|
||||
}, {success : _.bind(self.clearAndReactivateForm, self)});
|
||||
|
||||
},
|
||||
|
||||
clearAndReactivateForm : function() {
|
||||
this.model.trigger("interacted")
|
||||
this.toggleFormState()
|
||||
this.$("textarea").val("")
|
||||
.css('height', '18px')
|
||||
.focus()
|
||||
},
|
||||
|
||||
toggleFormState : function() {
|
||||
this.$("form").children().toggleClass('disabled')
|
||||
},
|
||||
|
||||
scrollToBottom : function() {
|
||||
$(this.scrollableArea).scrollTop($(this.scrollableArea).prop("scrollHeight"))
|
||||
}
|
||||
|
||||
});
|
||||
@@ -1,34 +0,0 @@
|
||||
app.views.PostViewerReactions = app.views.Base.extend({
|
||||
|
||||
className : "",
|
||||
|
||||
templateName: "post-viewer/reactions",
|
||||
|
||||
tooltipSelector : ".avatar",
|
||||
|
||||
initialize : function() {
|
||||
this.model.bind('interacted', this.render, this);
|
||||
},
|
||||
|
||||
postRenderTemplate : function() {
|
||||
this.populateComments()
|
||||
},
|
||||
|
||||
/* copy pasta from commentStream */
|
||||
populateComments : function() {
|
||||
this.model.comments.each(this.appendComment, this)
|
||||
},
|
||||
|
||||
/* copy pasta from commentStream */
|
||||
appendComment: function(comment) {
|
||||
// Set the post as the comment's parent, so we can check
|
||||
// on post ownership in the Comment view.
|
||||
comment.set({parent : this.model.toJSON()})
|
||||
|
||||
this.$("#post-comments").append(new app.views.Comment({
|
||||
model: comment,
|
||||
className : "post-comment media"
|
||||
}).render().el);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -1,44 +0,0 @@
|
||||
app.views.Post = app.views.StreamObject.extend({
|
||||
presenter : function() {
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
authorIsCurrentUser : this.authorIsCurrentUser(),
|
||||
showPost : this.showPost(),
|
||||
text : app.helpers.textFormatter(this.model)
|
||||
})
|
||||
},
|
||||
|
||||
authorIsCurrentUser : function() {
|
||||
return app.currentUser.authenticated() && this.model.get("author").id == app.user().id
|
||||
},
|
||||
|
||||
showPost : function() {
|
||||
return (app.currentUser.get("showNsfw")) || !this.model.get("nsfw")
|
||||
}
|
||||
}, { //static methods below
|
||||
|
||||
showFactory : function(model) {
|
||||
var frameName = model.get("frame_name");
|
||||
|
||||
if(_.include(app.models.Post.legacyTemplateNames, frameName)){
|
||||
return legacyShow(model)
|
||||
} else {
|
||||
return new app.views.Post[frameName]({
|
||||
model : model
|
||||
})
|
||||
}
|
||||
|
||||
function legacyShow(model) {
|
||||
return new app.views.Post.Legacy({
|
||||
model : model,
|
||||
className : frameName + " post loaded",
|
||||
templateName : "post-viewer/content/" + frameName
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
app.views.Post.Legacy = app.views.Post.extend({
|
||||
initialize : function(options) {
|
||||
this.templateName = options.templateName || this.templateName
|
||||
}
|
||||
})
|
||||
@@ -1,100 +0,0 @@
|
||||
//this file is the scary no-no-zone bad-touch of our backbone code.
|
||||
//after re-writing/eliminating the existing Publisher let's re-write
|
||||
//this with PANACHE! <333 Dennis
|
||||
|
||||
app.views.Publisher = Backbone.View.extend({
|
||||
|
||||
el : "#publisher",
|
||||
|
||||
events : {
|
||||
"focus textarea" : "open",
|
||||
"click #hide_publisher" : "clear",
|
||||
"submit form" : "createStatusMessage"
|
||||
},
|
||||
|
||||
initialize : function(){
|
||||
this.collection = this.collection //takes a Posts collection
|
||||
return this;
|
||||
},
|
||||
|
||||
createStatusMessage : function(evt) {
|
||||
if(evt){ evt.preventDefault(); }
|
||||
|
||||
var serializedForm = $(evt.target).closest("form").serializeObject();
|
||||
|
||||
// lulz this code should be killed.
|
||||
var statusMessage = new app.models.Post();
|
||||
|
||||
statusMessage.save({
|
||||
"status_message" : {
|
||||
"text" : serializedForm["status_message[text]"]
|
||||
},
|
||||
"aspect_ids" : serializedForm["aspect_ids[]"],
|
||||
"photos" : serializedForm["photos[]"],
|
||||
"services" : serializedForm["services[]"]
|
||||
}, {
|
||||
url : "/status_messages",
|
||||
success : function() {
|
||||
if(app.publisher) {
|
||||
$(app.publisher.el).trigger('ajax:success');
|
||||
}
|
||||
if(app.stream) {
|
||||
app.stream.posts.add(statusMessage.toJSON());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// clear state
|
||||
this.clear();
|
||||
},
|
||||
|
||||
clear : function() {
|
||||
this.$('textarea').val("");
|
||||
this.$('#publisher_textarea_wrapper').removeClass("with_attachments");
|
||||
|
||||
// remove photos
|
||||
this.$("#photodropzone").find('li').remove();
|
||||
this.$("input[name='photos[]']").remove();
|
||||
|
||||
// close publishing area (CSS)
|
||||
this.close();
|
||||
|
||||
Publisher.clear()
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
open : function() {
|
||||
$(this.el).removeClass('closed');
|
||||
this.$("#publisher_textarea_wrapper").addClass('active');
|
||||
this.$("textarea.ac_input").css('min-height', '42px');
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
close : function() {
|
||||
$(this.el).addClass("closed");
|
||||
this.$("#publisher_textarea_wrapper").removeClass("active");
|
||||
this.$("textarea.ac_input").css('min-height', '');
|
||||
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
// jQuery helper for serializing a <form> into JSON
|
||||
$.fn.serializeObject = function()
|
||||
{
|
||||
var o = {};
|
||||
var a = this.serializeArray();
|
||||
$.each(a, function() {
|
||||
if (o[this.name] !== undefined) {
|
||||
if (!o[this.name].push) {
|
||||
o[this.name] = [o[this.name]];
|
||||
}
|
||||
o[this.name].push(this.value || '');
|
||||
} else {
|
||||
o[this.name] = this.value || '';
|
||||
}
|
||||
});
|
||||
return o;
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
app.views.StreamFaces = app.views.Base.extend({
|
||||
|
||||
templateName : "stream-faces",
|
||||
|
||||
className : "stream-faces",
|
||||
|
||||
tooltipSelector : ".avatar",
|
||||
|
||||
initialize : function(){
|
||||
this.updatePeople()
|
||||
app.stream.posts.bind("add", this.updatePeople, this)
|
||||
},
|
||||
|
||||
presenter : function() {
|
||||
return {people : this.people}
|
||||
},
|
||||
|
||||
updatePeople : function(){
|
||||
if(this.people && this.people.length >= 15) { return }
|
||||
this.people = _(this.collection.models).chain()
|
||||
.map(function(post){ return post.get("author") })
|
||||
.compact()
|
||||
.uniq(false, function(person){ return person.id })
|
||||
.value()
|
||||
.slice(0,15);
|
||||
|
||||
this.render();
|
||||
}
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
app.views.StreamObject = app.views.Base.extend({
|
||||
destroyModel: function(evt) {
|
||||
if (evt) {
|
||||
evt.preventDefault();
|
||||
}
|
||||
if (!confirm(Diaspora.I18n.t("confirm_dialog"))) {
|
||||
return
|
||||
}
|
||||
|
||||
this.model.destroy();
|
||||
this.slideAndRemove();
|
||||
},
|
||||
|
||||
slideAndRemove : function() {
|
||||
$(this.el).slideUp(400, function() {
|
||||
$(this).remove();
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,119 +0,0 @@
|
||||
app.views.Stream = Backbone.View.extend({
|
||||
|
||||
events: {
|
||||
"click #paginate": "render"
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
this.stream = this.model
|
||||
this.collection = this.model.posts
|
||||
|
||||
this.setupEvents()
|
||||
this.setupInfiniteScroll()
|
||||
this.setupLightbox()
|
||||
this.postViews = []
|
||||
},
|
||||
|
||||
setupEvents : function(){
|
||||
this.stream.bind("fetched", this.removeLoader, this)
|
||||
this.stream.bind("fetched", this.postRender, this)
|
||||
this.stream.bind("allPostsLoaded", this.unbindInfScroll, this)
|
||||
this.collection.bind("add", this.addPost, this);
|
||||
if(window.app.user()) {
|
||||
app.user().bind("nsfwChanged", function() {
|
||||
_.map(this.postViews, function(view){ view.render() })
|
||||
}, this)
|
||||
}
|
||||
},
|
||||
|
||||
addPost : function(post) {
|
||||
var postView = new app.views.StreamPost({ model: post });
|
||||
|
||||
$(this.el)[
|
||||
(this.collection.at(0).id == post.id)
|
||||
? "prepend"
|
||||
: "append"
|
||||
](postView.render().el);
|
||||
|
||||
this.postViews.push(postView)
|
||||
return this;
|
||||
},
|
||||
|
||||
unbindInfScroll : function() {
|
||||
$(window).unbind("scroll");
|
||||
},
|
||||
|
||||
render : function(evt) {
|
||||
if(evt) { evt.preventDefault(); }
|
||||
|
||||
// fetch more posts from the stream model
|
||||
if(this.stream.fetch()) {
|
||||
this.appendLoader()
|
||||
};
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
postRender : function() {
|
||||
// collapse long posts
|
||||
var collHeight = 420,
|
||||
collElem = $(this.el).find(".collapsible");
|
||||
|
||||
_.each(collElem, function(elem) {
|
||||
var elem = $(elem),
|
||||
oembed = elem.find(".oembed"),
|
||||
addHeight = 0;
|
||||
|
||||
if( $.trim(oembed.html()) != "" ) {
|
||||
addHeight = oembed.height();
|
||||
}
|
||||
|
||||
// only collapse if height exceeds collHeight+20%
|
||||
if( elem.height() > ((collHeight*1.2)+addHeight) && !elem.is(".opened") ) {
|
||||
elem.data("orig-height", elem.height() );
|
||||
elem
|
||||
.height( Math.max(collHeight, addHeight) )
|
||||
.addClass("collapsed")
|
||||
.append(
|
||||
$('<div />')
|
||||
.addClass('expander')
|
||||
.text( Diaspora.I18n.t("show_more") )
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
appendLoader: function(){
|
||||
$("#paginate").html($("<img>", {
|
||||
src : "/images/static-loader.png",
|
||||
"class" : "loader"
|
||||
}));
|
||||
},
|
||||
|
||||
removeLoader: function() {
|
||||
$("#paginate").empty();
|
||||
},
|
||||
|
||||
setupLightbox : function(){
|
||||
this.lightbox = Diaspora.BaseWidget.instantiate("Lightbox");
|
||||
$(this.el).delegate("a.stream-photo-link", "click", this.lightbox.lightboxImageClicked);
|
||||
},
|
||||
|
||||
setupInfiniteScroll : function() {
|
||||
var throttledScroll = _.throttle($.proxy(this.infScroll, this), 200);
|
||||
$(window).scroll(throttledScroll);
|
||||
},
|
||||
|
||||
infScroll : function() {
|
||||
var $window = $(window);
|
||||
var distFromTop = $window.height() + $window.scrollTop();
|
||||
var distFromBottom = $(document).height() - distFromTop;
|
||||
var bufferPx = 500;
|
||||
|
||||
if(distFromBottom < bufferPx) {
|
||||
this.render();
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
});
|
||||
@@ -1,29 +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.
|
||||
*/
|
||||
|
||||
function toggleAspectTitle(){
|
||||
$("#aspect_name_title").toggleClass('hidden');
|
||||
$("#aspect_name_edit").toggleClass('hidden');
|
||||
}
|
||||
|
||||
function updateAspectName(new_name) {
|
||||
$('#aspect_name_title .name').html(new_name);
|
||||
$('input#aspect_name').val(new_name);
|
||||
}
|
||||
function updatePageAspectName( an_id, new_name) {
|
||||
$('ul#aspect_nav [data-guid="'+an_id+'"]').html(new_name);
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#rename_aspect_link').live('click', function(){
|
||||
toggleAspectTitle();
|
||||
});
|
||||
|
||||
$('form.edit_aspect').live('ajax:success', function(evt, data, status, xhr) {
|
||||
updateAspectName(data['name']);
|
||||
updatePageAspectName( data['id'], data['name'] );
|
||||
toggleAspectTitle();
|
||||
});
|
||||
});
|
||||
@@ -1,18 +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.
|
||||
*/
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#aspect_nav.left_nav .all_aspects .sub_nav').sortable({
|
||||
items: "li[data-aspect_id]",
|
||||
update: function(event, ui) {
|
||||
var order = $(this).sortable("toArray", {attribute: "data-aspect_id"}),
|
||||
obj = { 'reorder_aspects': order, '_method': 'put' };
|
||||
$.ajax('/user', { type: 'post', dataType: 'script', data: obj });
|
||||
},
|
||||
revert: true,
|
||||
helper: 'clone'
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,61 +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.
|
||||
|
||||
var AspectsDropdown = {
|
||||
updateNumber: function(dropdown, personId, number, inAspectClass){
|
||||
var button = dropdown.parents(".dropdown").children('.button.toggle'),
|
||||
selectedAspects = dropdown.children(".selected").length,
|
||||
allAspects = dropdown.children().length,
|
||||
replacement;
|
||||
|
||||
if (number == 0) {
|
||||
button.removeClass(inAspectClass);
|
||||
if( dropdown.closest('#publisher').length ) {
|
||||
replacement = Diaspora.I18n.t("aspect_dropdown.select_aspects");
|
||||
} else {
|
||||
replacement = Diaspora.I18n.t("aspect_dropdown.add_to_aspect");
|
||||
/* flash message prompt */
|
||||
var message = Diaspora.I18n.t("aspect_dropdown.stopped_sharing_with", {name: dropdown.data('person-short-name')});
|
||||
Diaspora.page.flashMessages.render({success: true, notice: message});
|
||||
}
|
||||
}else if (selectedAspects == allAspects) {
|
||||
replacement = Diaspora.I18n.t('aspect_dropdown.all_aspects');
|
||||
}else if (number == 1) {
|
||||
button.addClass(inAspectClass);
|
||||
replacement = dropdown.find(".selected").first().text();
|
||||
/* flash message prompt */
|
||||
if( dropdown.closest('#publisher').length == 0 ) {
|
||||
var message = Diaspora.I18n.t("aspect_dropdown.started_sharing_with", {name: dropdown.data('person-short-name')});
|
||||
Diaspora.page.flashMessages.render({success: true, notice: message});
|
||||
}
|
||||
}else {
|
||||
replacement = Diaspora.I18n.t('aspect_dropdown.toggle', { count: number.toString()})
|
||||
}
|
||||
|
||||
button.text(replacement + ' ▼');
|
||||
},
|
||||
|
||||
toggleCheckbox: function(check) {
|
||||
if(!check.hasClass('radio')){
|
||||
var selectedAspects = check.closest(".dropdown").find("li.radio");
|
||||
AspectsDropdown.uncheckGroup(selectedAspects);
|
||||
}
|
||||
|
||||
check.toggleClass('selected');
|
||||
},
|
||||
|
||||
toggleRadio: function(check) {
|
||||
var selectedAspects = check.closest(".dropdown").find("li");
|
||||
|
||||
AspectsDropdown.uncheckGroup(selectedAspects);
|
||||
AspectsDropdown.toggleCheckbox(check);
|
||||
},
|
||||
|
||||
uncheckGroup: function(elements){
|
||||
$.each(elements, function(index, value) {
|
||||
$(value).removeClass('selected');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,98 +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.
|
||||
|
||||
var ContactEdit = {
|
||||
init: function(){
|
||||
$.extend(ContactEdit, AspectsDropdown);
|
||||
$('.dropdown.aspect_membership .dropdown_list > li, .dropdown.inviter .dropdown_list > li').live('click', function(evt){
|
||||
ContactEdit.processClick($(this), evt);
|
||||
});
|
||||
},
|
||||
|
||||
updateNumber: function(dropdown, personId, number){
|
||||
var button = dropdown.parents(".dropdown").children('.button.toggle'),
|
||||
replacement;
|
||||
|
||||
if (number == 0) {
|
||||
button.removeClass("in_aspects");
|
||||
replacement = Diaspora.I18n.t("aspect_dropdown.toggle.zero");
|
||||
}else if (number == 1) {
|
||||
button.addClass("in_aspects");
|
||||
replacement = dropdown.find(".selected").first().text();
|
||||
}else if (number < 3) {
|
||||
replacement = Diaspora.I18n.t('aspect_dropdown.toggle.few', { count: number.toString()})
|
||||
}else if (number > 3) {
|
||||
replacement = Diaspora.I18n.t('aspect_dropdown.toggle.many', { count: number.toString()})
|
||||
}else {
|
||||
//the above one are a tautology, but I want to have them here once for once we figure out a neat way i18n them
|
||||
replacement = Diaspora.I18n.t('aspect_dropdown.toggle.other', { count: number.toString()})
|
||||
ContactEdit.toggleAspectMembership(li, evt);
|
||||
}
|
||||
},
|
||||
|
||||
inviteFriend: function(li, evt) {
|
||||
$.post('/services/inviter/facebook.json', {
|
||||
"aspect_id" : li.data("aspect_id"),
|
||||
"uid" : li.parent().data("service_uid")
|
||||
}, function(data){
|
||||
ContactEdit.processSuccess(li, evt, data);
|
||||
});
|
||||
},
|
||||
|
||||
processSuccess: function(element, evt, data) {
|
||||
element.removeClass('loading')
|
||||
if (data.url != undefined) {
|
||||
window.location = data.url;
|
||||
} else {
|
||||
element.toggleClass("selected");
|
||||
Diaspora.widgets.flashes.render({'success':true, 'notice':data.message});
|
||||
}
|
||||
},
|
||||
|
||||
processClick: function(li, evt){
|
||||
var dropdown = li.closest('.dropdown');
|
||||
li.addClass('loading');
|
||||
if (dropdown.hasClass('inviter')) {
|
||||
ContactEdit.inviteFriend(li, evt);
|
||||
dropdown.html('sending, please wait...');
|
||||
}
|
||||
else {
|
||||
ContactEdit.toggleAspectMembership(li, evt);
|
||||
}
|
||||
},
|
||||
|
||||
toggleAspectMembership: function(li, evt) {
|
||||
var button = li.find('.button'),
|
||||
dropdown = li.closest('.dropdown'),
|
||||
dropdownList = li.parent('.dropdown_list');
|
||||
|
||||
if(button.hasClass('disabled') || li.hasClass('newItem')){ return; }
|
||||
|
||||
var selected = li.hasClass("selected"),
|
||||
routedId = selected ? "/42" : "";
|
||||
|
||||
$.post("/aspect_memberships" + routedId + ".json", {
|
||||
"aspect_id": li.data("aspect_id"),
|
||||
"person_id": li.parent().data("person_id"),
|
||||
"_method": (selected) ? "DELETE" : "POST"
|
||||
}, function(aspectMembership) {
|
||||
ContactEdit.toggleCheckbox(li);
|
||||
ContactEdit.updateNumber(li.closest(".dropdown_list"), li.parent().data("person_id"), aspectMembership.aspect_ids.length, 'in_aspects');
|
||||
|
||||
Diaspora.page.publish("aspectDropdown/updated", [li.parent().data("person_id"), li.parents(".dropdown").parent(".right").html()]);
|
||||
})
|
||||
.error(function() {
|
||||
var message = Diaspora.I18n.t("aspect_dropdown.error", {name: dropdownList.data('person-short-name')});
|
||||
Diaspora.page.flashMessages.render({success: false, notice: message});
|
||||
dropdown.removeClass('active');
|
||||
})
|
||||
.complete(function() {
|
||||
li.removeClass("loading");
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(function(){
|
||||
ContactEdit.init();
|
||||
});
|
||||
@@ -1,82 +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.
|
||||
*/
|
||||
|
||||
var List = {
|
||||
initialize: function() {
|
||||
$(".contact_list_search").live("keyup", function(e) {
|
||||
var search = $(this);
|
||||
var list = $(".contacts", ".searchable");
|
||||
var query = new RegExp(search.val(),'i');
|
||||
|
||||
$("> .contact", list).each( function(idx, element) {
|
||||
element = $(element);
|
||||
if( !element.find(".name").text().match(query) ) {
|
||||
element.addClass('hidden');
|
||||
} else {
|
||||
element.removeClass('hidden');
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
disconnectUser: function(contact_id){
|
||||
$.ajax({
|
||||
url: "/contacts/" + contact_id,
|
||||
type: "DELETE",
|
||||
success: function(){
|
||||
if( $('.searchable').length == 1){
|
||||
$('.searchable .contact[data-contact_id='+contact_id+']').fadeOut(200);
|
||||
} else if($('#aspects_list').length == 1) {
|
||||
$.facebox.close();
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
runDelayedSearch: function( searchTerm ) {
|
||||
$.getJSON('/people/refresh_search',
|
||||
{ q: searchTerm },
|
||||
List.handleSearchRefresh
|
||||
);
|
||||
},
|
||||
|
||||
handleSearchRefresh: function( data ) {
|
||||
var streamEl = $("#people_stream.stream");
|
||||
var string = data.search_html || $("<p>", {
|
||||
text : Diaspora.I18n.t("people.not_found")
|
||||
});
|
||||
|
||||
streamEl.html(string);
|
||||
},
|
||||
|
||||
startSearchDelay: function (theSearch) {
|
||||
setTimeout( "List.runDelayedSearch('" + theSearch + "')", 10000);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
$('.added').bind('ajax:loading', function() {
|
||||
var $this = $(this);
|
||||
|
||||
$this.addClass('disabled');
|
||||
$this.fadeTo(200,0.4);
|
||||
});
|
||||
|
||||
$('.added').bind('hover',
|
||||
function() {
|
||||
var $this = $(this)
|
||||
$this.addClass("remove");
|
||||
$this.children("img").attr("src","/images/icons/monotone_close_exit_delete.png");
|
||||
},
|
||||
|
||||
function() {
|
||||
var $this = $(this)
|
||||
$this.removeClass("remove");
|
||||
$this.children("img").attr("src","/images/icons/monotone_check_yes.png");
|
||||
});
|
||||
|
||||
List.initialize();
|
||||
});
|
||||
@@ -1,95 +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.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var Diaspora = {
|
||||
Pages: {},
|
||||
Widgets: {}
|
||||
};
|
||||
|
||||
Diaspora.EventBroker = {
|
||||
extend: function(Klass) {
|
||||
var whatToExtend = (typeof Klass === "function") ? Klass.prototype : Klass;
|
||||
|
||||
$.extend(whatToExtend, {
|
||||
eventsContainer: $({}),
|
||||
publish: function(eventName, args) {
|
||||
var eventNames = eventName.split(" ");
|
||||
|
||||
for(eventName in eventNames) {
|
||||
this.eventsContainer.trigger(eventNames[eventName], args);
|
||||
}
|
||||
},
|
||||
subscribe: function(eventName, callback, context) {
|
||||
var eventNames = eventName.split(" ");
|
||||
|
||||
for(eventName in eventNames) {
|
||||
this.eventsContainer.bind(eventNames[eventName], $.proxy(callback, context));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return whatToExtend;
|
||||
}
|
||||
};
|
||||
|
||||
Diaspora.BaseWidget = {
|
||||
instantiate: function(Widget, element) {
|
||||
$.extend(Diaspora.Widgets[Widget].prototype, Diaspora.EventBroker.extend(Diaspora.BaseWidget));
|
||||
|
||||
var widget = new Diaspora.Widgets[Widget](),
|
||||
args = Array.prototype.slice.call(arguments, 1);
|
||||
|
||||
widget.publish("widget/ready", args);
|
||||
|
||||
return widget;
|
||||
},
|
||||
|
||||
globalSubscribe: function(eventName, callback, context) {
|
||||
Diaspora.page.subscribe(eventName, callback, context);
|
||||
},
|
||||
|
||||
globalPublish: function(eventName, args) {
|
||||
Diaspora.page.publish(eventName, args);
|
||||
}
|
||||
};
|
||||
|
||||
Diaspora.BasePage = function(body) {
|
||||
$.extend(this, Diaspora.BaseWidget);
|
||||
$.extend(this, {
|
||||
directionDetector: this.instantiate("DirectionDetector"),
|
||||
events: function() { return Diaspora.page.eventsContainer.data("events"); },
|
||||
flashMessages: this.instantiate("FlashMessages"),
|
||||
header: this.instantiate("Header", body.find("header")),
|
||||
hoverCard: this.instantiate("HoverCard", body.find("#hovercard")),
|
||||
timeAgo: this.instantiate("TimeAgo")
|
||||
});
|
||||
};
|
||||
|
||||
Diaspora.instantiatePage = function() {
|
||||
if (typeof Diaspora.Pages[Diaspora.Page] === "undefined") {
|
||||
Diaspora.page = Diaspora.EventBroker.extend(Diaspora.BaseWidget);
|
||||
} else {
|
||||
var Page = Diaspora.Pages[Diaspora.Page];
|
||||
$.extend(Page.prototype, Diaspora.EventBroker.extend(Diaspora.BaseWidget));
|
||||
|
||||
Diaspora.page = new Page();
|
||||
}
|
||||
|
||||
if(!$.mobile)//why does this need this?
|
||||
$.extend(Diaspora.page, new Diaspora.BasePage($(document.body)));
|
||||
Diaspora.page.publish("page/ready", [$(document.body)])
|
||||
};
|
||||
|
||||
// temp hack to check if backbone is enabled for the page
|
||||
Diaspora.backboneEnabled = function(){
|
||||
return window.app && window.app.stream !== undefined;
|
||||
}
|
||||
|
||||
window.Diaspora = Diaspora;
|
||||
})();
|
||||
|
||||
|
||||
$(Diaspora.instantiatePage);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,25 +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.
|
||||
*/
|
||||
|
||||
var FriendFinder = {
|
||||
|
||||
initialize: function() {
|
||||
$('.contact_list .button').click(function(){
|
||||
$this = $(this);
|
||||
var uid = $this.parents('li').attr("uid");
|
||||
$this.parents('ul').children("#options_"+uid).slideToggle(function(){
|
||||
if($this.text() == 'Done'){
|
||||
$this.text($this.attr('old-text'));
|
||||
} else {
|
||||
$this.attr('old-text', $this.text());
|
||||
$this.text('Done');
|
||||
}
|
||||
$(this).toggleClass('hidden');
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(FriendFinder.initialize);
|
||||
@@ -1,30 +0,0 @@
|
||||
Diaspora.Alert = {
|
||||
faceboxTemplate:
|
||||
'<div id="diaspora_alert">' +
|
||||
'<div class="span-12 last">' +
|
||||
'<div id="facebox_header">' +
|
||||
'<h4>' +
|
||||
'<%= title %>' +
|
||||
'</h4>' +
|
||||
'</div>' +
|
||||
'<%= content %>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
|
||||
show: function(title, content) {
|
||||
$(_.template(this.faceboxTemplate, {
|
||||
title: title,
|
||||
content: content
|
||||
})).appendTo(document.body);
|
||||
|
||||
$.facebox({
|
||||
div: "#diaspora_alert"
|
||||
}, "diaspora_alert");
|
||||
}
|
||||
};
|
||||
|
||||
$(function() {
|
||||
$(document).bind("close.facebox", function() {
|
||||
$("#diaspora_alert").remove();
|
||||
});
|
||||
});
|
||||
@@ -1,39 +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.
|
||||
*/
|
||||
Diaspora.I18n = {
|
||||
language: "en",
|
||||
locale: {},
|
||||
|
||||
loadLocale: function(locale, language) {
|
||||
this.locale = locale;
|
||||
this.language = language;
|
||||
rule = this.t('pluralization_rule');
|
||||
if (rule === "")
|
||||
rule = 'function (n) { return n == 1 ? "one" : "other" }';
|
||||
eval("this.pluralizationKey = "+rule);
|
||||
},
|
||||
|
||||
t: function(item, views) {
|
||||
var items = item.split("."),
|
||||
translatedMessage,
|
||||
nextNamespace;
|
||||
|
||||
while(nextNamespace = items.shift()) {
|
||||
translatedMessage = (translatedMessage)
|
||||
? translatedMessage[nextNamespace]
|
||||
: this.locale[nextNamespace];
|
||||
|
||||
if(typeof translatedMessage === "undefined") {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
if(views && typeof views.count !== "undefined") {
|
||||
translatedMessage = translatedMessage[this.pluralizationKey(views.count)];
|
||||
}
|
||||
|
||||
return _.template(translatedMessage, views || {});
|
||||
}
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
document.createElement('header');
|
||||
document.createElement('footer');
|
||||
|
||||
@@ -1,93 +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.
|
||||
*/
|
||||
|
||||
$(document).ready(function(){
|
||||
|
||||
$('a.conversation').live('click', function(){
|
||||
$.getScript(this.href, function() {
|
||||
Diaspora.page.directionDetector.updateBinds();
|
||||
});
|
||||
history.pushState(null, "", this.href);
|
||||
|
||||
var conv = $(this).children('.stream_element'),
|
||||
cBadge = $("#message_inbox_badge").children(".badge_count");
|
||||
if(conv.hasClass('unread') ){
|
||||
conv.removeClass('unread');
|
||||
}
|
||||
if(cBadge.html() !== null) {
|
||||
cBadge.html().replace(/\d+/, function(num){
|
||||
num = parseInt(num);
|
||||
cBadge.html(parseInt(num)-1);
|
||||
if(num == 1) {
|
||||
cBadge.addClass("hidden");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
jQuery("abbr.timeago").timeago();
|
||||
return false;
|
||||
});
|
||||
|
||||
$(window).bind("popstate", function(){
|
||||
if (location.href.match(/conversations\/\d+/) !== null) {
|
||||
$.getScript(location.href, function() {
|
||||
Diaspora.page.directionDetector.updateBinds();
|
||||
});
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
resize();
|
||||
$(window).resize(function(){
|
||||
resize();
|
||||
});
|
||||
|
||||
$('#conversation_inbox .stream').infinitescroll({
|
||||
navSelector : ".pagination",
|
||||
// selector for the paged navigation (it will be hidden)
|
||||
nextSelector : ".pagination a.next_page",
|
||||
// selector for the NEXT link (to page 2)
|
||||
itemSelector : "#conversation_inbox .conversation",
|
||||
// selector for all items you'll retrieve
|
||||
localMode: true,
|
||||
debug: false,
|
||||
donetext: "no more.",
|
||||
loadingText: "",
|
||||
loadingImg: '/images/ajax-loader.gif'
|
||||
}, function(){
|
||||
$('.conversation', '.stream').bind('mousedown', function(){
|
||||
bindIt($(this));
|
||||
});
|
||||
});
|
||||
|
||||
// kill scroll binding
|
||||
$(window).unbind('.infscr');
|
||||
|
||||
// hook up the manual click guy.
|
||||
$('a.next_page').click(function(){
|
||||
$(document).trigger('retrieve.infscr');
|
||||
return false;
|
||||
});
|
||||
|
||||
// remove the paginator when we're done.
|
||||
$(document).ajaxError(function(e,xhr,opt){
|
||||
if (xhr.status == 404) { $('a.next_page').remove(); }
|
||||
});
|
||||
|
||||
$('#reply_to_conversation').live('click', function(evt) {
|
||||
evt.preventDefault();
|
||||
$('html, body').animate({scrollTop:$(window).height()}, 'medium', function(){
|
||||
$('#message_text').focus();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
var resize = function(){
|
||||
var inboxSidebar = $('#conversation_inbox'),
|
||||
inboxSidebarOffset = inboxSidebar.offset().top,
|
||||
windowHeight = $(window).height();
|
||||
|
||||
inboxSidebar.css('height', windowHeight - inboxSidebarOffset);
|
||||
};
|
||||
@@ -1,763 +0,0 @@
|
||||
/*
|
||||
* Autocomplete - jQuery plugin 1.1pre
|
||||
*
|
||||
* Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
|
||||
*
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*
|
||||
* Revision: $Id: jquery.autocomplete.js 5785 2008-07-12 10:37:33Z joern.zaefferer $
|
||||
* Modified by Diaspora
|
||||
*/
|
||||
|
||||
;(function($) {
|
||||
|
||||
$.fn.extend({
|
||||
autocomplete: function(urlOrData, options) {
|
||||
var isUrl = typeof urlOrData == "string";
|
||||
options = $.extend({}, $.Autocompleter.defaults, {
|
||||
url: isUrl ? urlOrData : null,
|
||||
data: isUrl ? null : urlOrData,
|
||||
delay: isUrl ? $.Autocompleter.defaults.delay : 10,
|
||||
max: options && !options.scroll ? 10 : 150
|
||||
}, options);
|
||||
|
||||
// if highlight is set to false, replace it with a do-nothing function
|
||||
options.highlight = options.highlight || function(value) { return value; };
|
||||
|
||||
// if the formatMatch option is not specified, then use formatItem for backwards compatibility
|
||||
options.formatMatch = options.formatMatch || options.formatItem;
|
||||
|
||||
return this.each(function() {
|
||||
new $.Autocompleter(this, options);
|
||||
});
|
||||
},
|
||||
result: function(handler) {
|
||||
return this.bind("result", handler);
|
||||
},
|
||||
search: function(handler) {
|
||||
return this.trigger("search", [handler]);
|
||||
},
|
||||
flushCache: function() {
|
||||
return this.trigger("flushCache");
|
||||
},
|
||||
setOptions: function(options){
|
||||
return this.trigger("setOptions", [options]);
|
||||
},
|
||||
unautocomplete: function() {
|
||||
return this.trigger("unautocomplete");
|
||||
}
|
||||
});
|
||||
|
||||
$.Autocompleter = function(input, options) {
|
||||
|
||||
var KEY = KEYCODES;
|
||||
|
||||
// Create $ object for input element
|
||||
var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
|
||||
|
||||
var timeout;
|
||||
var previousValue = "";
|
||||
var cache = $.Autocompleter.Cache(options);
|
||||
var hasFocus = 0;
|
||||
var lastKeyPressCode;
|
||||
var config = {
|
||||
mouseDownOnSelect: false
|
||||
};
|
||||
var select = $.Autocompleter.Select(options, input, selectCurrent, config);
|
||||
|
||||
var blockSubmit;
|
||||
|
||||
// prevent form submit in opera when selecting with return key
|
||||
$.browser.opera && $(input.form).bind("submit.autocomplete", function() {
|
||||
if (blockSubmit) {
|
||||
blockSubmit = false;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
|
||||
$input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
|
||||
// track last key pressed
|
||||
lastKeyPressCode = event.keyCode;
|
||||
switch(event.keyCode) {
|
||||
|
||||
case KEY.LEFT:
|
||||
case KEY.RIGHT:
|
||||
if( options.disableRightAndLeft && select.visible()){
|
||||
event.preventDefault();
|
||||
}
|
||||
break;
|
||||
case KEY.UP:
|
||||
if ( select.visible() ) {
|
||||
event.preventDefault();
|
||||
select.prev();
|
||||
} else {
|
||||
onChange(0, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY.DOWN:
|
||||
if ( select.visible() ) {
|
||||
event.preventDefault();
|
||||
select.next();
|
||||
} else {
|
||||
onChange(0, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY.PAGEUP:
|
||||
if ( select.visible() ) {
|
||||
event.preventDefault();
|
||||
select.pageUp();
|
||||
} else {
|
||||
onChange(0, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY.PAGEDOWN:
|
||||
if ( select.visible() ) {
|
||||
event.preventDefault();
|
||||
select.pageDown();
|
||||
} else {
|
||||
onChange(0, true);
|
||||
}
|
||||
break;
|
||||
|
||||
// matches also semicolon
|
||||
case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
|
||||
case KEY.TAB:
|
||||
case KEY.RETURN:
|
||||
if( selectCurrent() ) {
|
||||
// stop default to prevent a form submit, Opera needs special handling
|
||||
event.preventDefault();
|
||||
blockSubmit = true;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY.ESC:
|
||||
select.hide();
|
||||
break;
|
||||
|
||||
default:
|
||||
options.onLetterTyped(event, $input);
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(onChange, options.delay);
|
||||
break;
|
||||
}
|
||||
}).focus(function(){
|
||||
// track whether the field has focus, we shouldn't process any
|
||||
// results if the field no longer has focus
|
||||
hasFocus++;
|
||||
}).blur(function() {
|
||||
hasFocus = 0;
|
||||
if (!config.mouseDownOnSelect) {
|
||||
hideResults();
|
||||
}
|
||||
}).click(function() {
|
||||
// show select when clicking in a focused field
|
||||
if ( hasFocus++ > 1 && !select.visible() ) {
|
||||
onChange(0, true);
|
||||
}
|
||||
}).bind("search", function() {
|
||||
// TODO why not just specifying both arguments?
|
||||
var fn = (arguments.length > 1) ? arguments[1] : null;
|
||||
function findValueCallback(q, data) {
|
||||
var result;
|
||||
if( data && data.length ) {
|
||||
for (var i=0; i < data.length; i++) {
|
||||
if( data[i].result.toLowerCase() == q.toLowerCase() ) {
|
||||
result = data[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( typeof fn == "function" ) fn(result);
|
||||
else $input.trigger("result", result && [result.data, result.value]);
|
||||
}
|
||||
$.each(trimWords($input.val()), function(i, value) {
|
||||
request(value, findValueCallback, findValueCallback);
|
||||
});
|
||||
}).bind("flushCache", function() {
|
||||
cache.flush();
|
||||
}).bind("setOptions", function() {
|
||||
$.extend(options, arguments[1]);
|
||||
// if we've updated the data, repopulate
|
||||
if ( "data" in arguments[1] )
|
||||
cache.populate();
|
||||
}).bind("unautocomplete", function() {
|
||||
select.unbind();
|
||||
$input.unbind();
|
||||
$(input.form).unbind(".autocomplete");
|
||||
});
|
||||
|
||||
|
||||
function selectCurrent() {
|
||||
var selected = select.selected();
|
||||
if( !selected )
|
||||
return false;
|
||||
|
||||
var v = selected.result;
|
||||
previousValue = v;
|
||||
|
||||
if ( options.multiple ) {
|
||||
var words = trimWords($input.val());
|
||||
if ( words.length > 1 ) {
|
||||
v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v;
|
||||
}
|
||||
v += options.multipleSeparator;
|
||||
}
|
||||
|
||||
hideResultsNow();
|
||||
options.onSelect($input, selected.data, selected.value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function onChange(crap, skipPrevCheck) {
|
||||
if( lastKeyPressCode == KEY.DEL ) {
|
||||
select.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
var currentValue = $input.val();
|
||||
|
||||
if ( !skipPrevCheck && currentValue == previousValue )
|
||||
return;
|
||||
|
||||
previousValue = currentValue;
|
||||
|
||||
currentValue = options.searchTermFromValue(currentValue, $input[0].selectionStart);
|
||||
if ( currentValue.length >= options.minChars) {
|
||||
$input.addClass(options.loadingClass);
|
||||
if (!options.matchCase)
|
||||
currentValue = currentValue.toLowerCase();
|
||||
request(currentValue, receiveData, hideResultsNow);
|
||||
} else {
|
||||
stopLoading();
|
||||
select.hide();
|
||||
}
|
||||
};
|
||||
|
||||
function trimWords(value) {
|
||||
if ( !value ) {
|
||||
return [""];
|
||||
}
|
||||
var words = value.split( options.multipleSeparator );
|
||||
var result = [];
|
||||
$.each(words, function(i, value) {
|
||||
if ( $.trim(value) )
|
||||
result[i] = $.trim(value);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
// fills in the input box w/the first match (assumed to be the best match)
|
||||
// q: the term entered
|
||||
// sValue: the first matching result
|
||||
function autoFill(q, sValue){
|
||||
// autofill in the complete box w/the first match as long as the user hasn't entered in more data
|
||||
// if the last user key pressed was backspace, don't autofill
|
||||
if( options.autoFill && (options.lastWord($input.val(), null, options.multiple).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
|
||||
// fill in the value (keep the case the user has typed)
|
||||
$input.val($input.val() + sValue.substring(options.lastWord(previousValue, null, options.multiple).length));
|
||||
// select the portion of the value not typed by the user (so the next character will erase)
|
||||
$.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
|
||||
}
|
||||
};
|
||||
|
||||
function hideResults() {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(hideResultsNow, 200);
|
||||
};
|
||||
|
||||
function hideResultsNow() {
|
||||
select.hide();
|
||||
clearTimeout(timeout);
|
||||
stopLoading();
|
||||
if (options.mustMatch) {
|
||||
// call search and run callback
|
||||
$input.search(
|
||||
function (result){
|
||||
// if no value found, clear the input box
|
||||
if( !result ) {
|
||||
if (options.multiple) {
|
||||
var words = trimWords($input.val()).slice(0, -1);
|
||||
$input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
|
||||
}
|
||||
else
|
||||
$input.val( "" );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function receiveData(q, data) {
|
||||
if ( data && data.length && hasFocus ) {
|
||||
stopLoading();
|
||||
select.display(data, q);
|
||||
autoFill(q, data[0].value);
|
||||
select.show();
|
||||
} else {
|
||||
hideResultsNow();
|
||||
}
|
||||
};
|
||||
|
||||
function request(term, success, failure) {
|
||||
if (!options.matchCase)
|
||||
term = term.toLowerCase();
|
||||
var data = cache.load(term);
|
||||
// recieve the cached data
|
||||
if (data && data.length) {
|
||||
success(term, data);
|
||||
// if an AJAX url has been supplied, try loading the data now
|
||||
} else if( (typeof options.url == "string") && (options.url.length > 0) ){
|
||||
|
||||
var extraParams = {
|
||||
timestamp: +new Date()
|
||||
};
|
||||
$.each(options.extraParams, function(key, param) {
|
||||
extraParams[key] = typeof param == "function" ? param() : param;
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
// try to leverage ajaxQueue plugin to abort previous requests
|
||||
mode: "abort",
|
||||
// limit abortion to this input
|
||||
port: "autocomplete" + input.name,
|
||||
dataType: options.dataType,
|
||||
url: options.url,
|
||||
data: $.extend({
|
||||
q: options.lastWord(term, null, options.multiple),
|
||||
limit: options.max
|
||||
}, extraParams),
|
||||
success: function(data) {
|
||||
var parsed = options.parse && options.parse(data) || parse(data);
|
||||
cache.add(term, parsed);
|
||||
success(term, parsed);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
|
||||
select.emptyList();
|
||||
failure(term);
|
||||
}
|
||||
};
|
||||
|
||||
function parse(data) {
|
||||
var parsed = [];
|
||||
var rows = data.split("\n");
|
||||
for (var i=0; i < rows.length; i++) {
|
||||
var row = $.trim(rows[i]);
|
||||
if (row) {
|
||||
row = row.split("|");
|
||||
parsed[parsed.length] = {
|
||||
data: row,
|
||||
value: row[0],
|
||||
result: options.formatResult && options.formatResult(row, row[0]) || row[0]
|
||||
};
|
||||
}
|
||||
}
|
||||
return parsed;
|
||||
};
|
||||
|
||||
function stopLoading() {
|
||||
$input.removeClass(options.loadingClass);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
$.Autocompleter.defaults = {
|
||||
onLetterTyped : function(event){},
|
||||
lastWord : function(value, crap, multiple) {
|
||||
if ( !multiple )
|
||||
return value;
|
||||
var words = trimWords(value);
|
||||
return words[words.length - 1];
|
||||
},
|
||||
inputClass: "ac_input",
|
||||
resultsClass: "ac_results",
|
||||
loadingClass: "ac_loading",
|
||||
onSelect: function(input, data, formatted){
|
||||
if (select.visible())
|
||||
// position cursor at end of input field
|
||||
$.Autocompleter.Selection(input, input.value.length, input.value.length);
|
||||
input.val(formatted);
|
||||
},
|
||||
minChars: 1,
|
||||
delay: 400,
|
||||
matchCase: false,
|
||||
matchSubset: true,
|
||||
matchContains: false,
|
||||
cacheLength: 10,
|
||||
max: 100,
|
||||
mustMatch: false,
|
||||
extraParams: {},
|
||||
selectFirst: true,
|
||||
formatItem: function(row) { return row[0]; },
|
||||
selectionChanged : function(newItem) {},
|
||||
formatMatch: null,
|
||||
autoFill: false,
|
||||
width: 0,
|
||||
multiple: false,
|
||||
multipleSeparator: ", ",
|
||||
disableRightAndLeft: false,
|
||||
highlight: function(value, term) {
|
||||
return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
|
||||
},
|
||||
scroll: true,
|
||||
scrollHeight: 180
|
||||
};
|
||||
$.Autocompleter.defaults.searchTermFromValue = $.Autocompleter.defaults.lastWord;
|
||||
|
||||
$.Autocompleter.Cache = function(options) {
|
||||
|
||||
var data = {};
|
||||
var length = 0;
|
||||
|
||||
function matchSubset(s, sub) {
|
||||
if (!options.matchCase)
|
||||
s = s.toLowerCase();
|
||||
var i = s.indexOf(sub);
|
||||
if (options.matchContains == "word"){
|
||||
i = s.toLowerCase().search("\\b" + sub.toLowerCase());
|
||||
}
|
||||
if (i == -1) return false;
|
||||
return i == 0 || options.matchContains;
|
||||
};
|
||||
|
||||
function add(q, value) {
|
||||
if (length > options.cacheLength){
|
||||
flush();
|
||||
}
|
||||
if (!data[q]){
|
||||
length++;
|
||||
}
|
||||
data[q] = value;
|
||||
}
|
||||
|
||||
function populate(){
|
||||
if( !options.data ) return false;
|
||||
// track the matches
|
||||
var stMatchSets = {},
|
||||
nullData = 0;
|
||||
|
||||
// no url was specified, we need to adjust the cache length to make sure it fits the local data store
|
||||
if( !options.url ) options.cacheLength = 1;
|
||||
|
||||
// track all options for minChars = 0
|
||||
stMatchSets[""] = [];
|
||||
|
||||
// loop through the array and create a lookup structure
|
||||
for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
|
||||
var rawValue = options.data[i];
|
||||
// if rawValue is a string, make an array otherwise just reference the array
|
||||
rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
|
||||
|
||||
var value = options.formatMatch(rawValue, i+1, options.data.length);
|
||||
if ( value === false )
|
||||
continue;
|
||||
|
||||
var firstChar = value.charAt(0).toLowerCase();
|
||||
// if no lookup array for this character exists, look it up now
|
||||
if( !stMatchSets[firstChar] )
|
||||
stMatchSets[firstChar] = [];
|
||||
|
||||
// if the match is a string
|
||||
var row = {
|
||||
value: value,
|
||||
data: rawValue,
|
||||
result: options.formatResult && options.formatResult(rawValue) || value
|
||||
};
|
||||
|
||||
// push the current match into the set list
|
||||
stMatchSets[firstChar].push(row);
|
||||
|
||||
// keep track of minChars zero items
|
||||
if ( nullData++ < options.max ) {
|
||||
stMatchSets[""].push(row);
|
||||
}
|
||||
};
|
||||
|
||||
// add the data items to the cache
|
||||
$.each(stMatchSets, function(i, value) {
|
||||
// increase the cache size
|
||||
options.cacheLength++;
|
||||
// add to the cache
|
||||
add(i, value);
|
||||
});
|
||||
}
|
||||
|
||||
// populate any existing data
|
||||
setTimeout(populate, 25);
|
||||
|
||||
function flush(){
|
||||
data = {};
|
||||
length = 0;
|
||||
}
|
||||
|
||||
return {
|
||||
flush: flush,
|
||||
add: add,
|
||||
populate: populate,
|
||||
load: function(q) {
|
||||
if (!options.cacheLength || !length)
|
||||
return null;
|
||||
/*
|
||||
* if dealing w/local data and matchContains than we must make sure
|
||||
* to loop through all the data collections looking for matches
|
||||
*/
|
||||
if( !options.url && options.matchContains ){
|
||||
// track all matches
|
||||
var csub = [];
|
||||
// loop through all the data grids for matches
|
||||
for( var k in data ){
|
||||
// don't search through the stMatchSets[""] (minChars: 0) cache
|
||||
// this prevents duplicates
|
||||
if( k.length > 0 ){
|
||||
var c = data[k];
|
||||
$.each(c, function(i, x) {
|
||||
// if we've got a match, add it to the array
|
||||
if (matchSubset(x.value, q)) {
|
||||
csub.push(x);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return csub;
|
||||
} else
|
||||
// if the exact item exists, use it
|
||||
if (data[q]){
|
||||
return data[q];
|
||||
} else
|
||||
if (options.matchSubset) {
|
||||
for (var i = q.length - 1; i >= options.minChars; i--) {
|
||||
var c = data[q.substr(0, i)];
|
||||
if (c) {
|
||||
var csub = [];
|
||||
$.each(c, function(i, x) {
|
||||
if (matchSubset(x.value, q)) {
|
||||
csub[csub.length] = x;
|
||||
}
|
||||
});
|
||||
return csub;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
$.Autocompleter.Select = function (options, input, select, config) {
|
||||
var CLASSES = {
|
||||
ACTIVE: "ac_over"
|
||||
};
|
||||
|
||||
var listItems,
|
||||
active = -1,
|
||||
data,
|
||||
term = "",
|
||||
needsInit = true,
|
||||
element,
|
||||
list;
|
||||
|
||||
// Create results
|
||||
function init() {
|
||||
if (!needsInit)
|
||||
return;
|
||||
element = $("<div/>")
|
||||
.hide()
|
||||
.addClass(options.resultsClass)
|
||||
.css("position", "absolute")
|
||||
.appendTo(document.body);
|
||||
|
||||
list = $("<ul/>").appendTo(element).mouseover( function(event) {
|
||||
if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
|
||||
active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
|
||||
$(target(event)).addClass(CLASSES.ACTIVE);
|
||||
}
|
||||
}).click(function(event) {
|
||||
$(target(event)).addClass(CLASSES.ACTIVE);
|
||||
select();
|
||||
// TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
|
||||
input.focus();
|
||||
return false;
|
||||
}).mousedown(function() {
|
||||
config.mouseDownOnSelect = true;
|
||||
}).mouseup(function() {
|
||||
config.mouseDownOnSelect = false;
|
||||
});
|
||||
|
||||
if( options.width > 0 )
|
||||
element.css("width", options.width);
|
||||
|
||||
needsInit = false;
|
||||
}
|
||||
|
||||
function target(event) {
|
||||
var element = event.target;
|
||||
while(element && element.tagName != "LI")
|
||||
element = element.parentNode;
|
||||
// more fun with IE, sometimes event.target is empty, just ignore it then
|
||||
if(!element)
|
||||
return [];
|
||||
return element;
|
||||
}
|
||||
|
||||
function moveSelect(step) {
|
||||
listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
|
||||
movePosition(step);
|
||||
var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
|
||||
if(options.scroll) {
|
||||
var offset = 0;
|
||||
listItems.slice(0, active).each(function() {
|
||||
offset += this.offsetHeight;
|
||||
});
|
||||
if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
|
||||
list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
|
||||
} else if(offset < list.scrollTop()) {
|
||||
list.scrollTop(offset);
|
||||
}
|
||||
}
|
||||
options.selectionChanged(activeItem);
|
||||
};
|
||||
|
||||
function movePosition(step) {
|
||||
active += step;
|
||||
if (active < 0) {
|
||||
active = listItems.size() - 1;
|
||||
} else if (active >= listItems.size()) {
|
||||
active = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function limitNumberOfItems(available) {
|
||||
return options.max && options.max < available
|
||||
? options.max
|
||||
: available;
|
||||
}
|
||||
|
||||
function fillList() {
|
||||
list.empty();
|
||||
var max = limitNumberOfItems(data.length);
|
||||
for (var i=0; i < max; i++) {
|
||||
if (!data[i])
|
||||
continue;
|
||||
var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
|
||||
if ( formatted === false )
|
||||
continue;
|
||||
var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
|
||||
$.data(li, "ac_data", data[i]);
|
||||
}
|
||||
listItems = list.find("li");
|
||||
if ( options.selectFirst ) {
|
||||
listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
|
||||
active = 0;
|
||||
}
|
||||
// apply bgiframe if available
|
||||
if ( $.fn.bgiframe )
|
||||
list.bgiframe();
|
||||
}
|
||||
|
||||
return {
|
||||
display: function(d, q) {
|
||||
init();
|
||||
data = d;
|
||||
term = q;
|
||||
fillList();
|
||||
},
|
||||
next: function() {
|
||||
moveSelect(1);
|
||||
},
|
||||
prev: function() {
|
||||
moveSelect(-1);
|
||||
},
|
||||
pageUp: function() {
|
||||
if (active != 0 && active - 8 < 0) {
|
||||
moveSelect( -active );
|
||||
} else {
|
||||
moveSelect(-8);
|
||||
}
|
||||
},
|
||||
pageDown: function() {
|
||||
if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
|
||||
moveSelect( listItems.size() - 1 - active );
|
||||
} else {
|
||||
moveSelect(8);
|
||||
}
|
||||
},
|
||||
hide: function() {
|
||||
element && element.hide();
|
||||
listItems && listItems.removeClass(CLASSES.ACTIVE);
|
||||
active = -1;
|
||||
},
|
||||
visible : function() {
|
||||
return element && element.is(":visible");
|
||||
},
|
||||
current: function() {
|
||||
return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
|
||||
},
|
||||
show: function() {
|
||||
var offset = $(input).offset();
|
||||
element.css({
|
||||
width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
|
||||
top: offset.top + input.offsetHeight,
|
||||
left: offset.left
|
||||
}).show();
|
||||
if(options.scroll) {
|
||||
list.scrollTop(0);
|
||||
list.css({
|
||||
maxHeight: options.scrollHeight,
|
||||
overflow: 'auto'
|
||||
});
|
||||
|
||||
if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
|
||||
var listHeight = 0;
|
||||
listItems.each(function() {
|
||||
listHeight += this.offsetHeight;
|
||||
});
|
||||
var scrollbarsVisible = listHeight > options.scrollHeight;
|
||||
list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
|
||||
if (!scrollbarsVisible) {
|
||||
// IE doesn't recalculate width when scrollbar disappears
|
||||
listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
selected: function() {
|
||||
var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
|
||||
return selected && selected.length && $.data(selected[0], "ac_data");
|
||||
},
|
||||
emptyList: function (){
|
||||
list && list.empty();
|
||||
},
|
||||
unbind: function() {
|
||||
element && element.remove();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
$.Autocompleter.Selection = function(field, start, end) {
|
||||
if( field.createTextRange ){
|
||||
var selRange = field.createTextRange();
|
||||
selRange.collapse(true);
|
||||
selRange.moveStart("character", start);
|
||||
selRange.moveEnd("character", end);
|
||||
selRange.select();
|
||||
} else if( field.setSelectionRange ){
|
||||
field.setSelectionRange(start, end);
|
||||
} else {
|
||||
if( field.selectionStart ){
|
||||
field.selectionStart = start;
|
||||
field.selectionEnd = end;
|
||||
}
|
||||
}
|
||||
field.focus();
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
@@ -1,621 +0,0 @@
|
||||
/*!
|
||||
// Infinite Scroll jQuery plugin
|
||||
// copyright Paul Irish, licensed GPL & MIT
|
||||
// version 2.0b1.110420
|
||||
|
||||
// home and docs: http://www.infinite-scroll.com
|
||||
// Modified by Diaspora:
|
||||
// A few callbacks were made options and generateInstanceID was make jquery 162 compatible
|
||||
*/
|
||||
|
||||
; (function ($) {
|
||||
|
||||
/* Define 'infinitescroll' function
|
||||
---------------------------------------------------*/
|
||||
|
||||
$.fn.infinitescroll = function infscr(options, callback) {
|
||||
|
||||
// grab each selector option and see if any fail.
|
||||
function areSelectorsValid(opts) {
|
||||
var debug = $.fn.infinitescroll._debug;
|
||||
for (var key in opts) {
|
||||
if (key.indexOf && key.indexOf('Selector') > -1 && $(opts[key]).length === 0) {
|
||||
debug('Your ' + key + ' found no elements.');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// find the number to increment in the path.
|
||||
function determinePath(path) {
|
||||
|
||||
if ($.isFunction(opts.pathParse)) {
|
||||
|
||||
debug('pathParse');
|
||||
return [path];
|
||||
|
||||
} else if (path.match(/^(.*?)\b2\b(.*?$)/)) {
|
||||
path = path.match(/^(.*?)\b2\b(.*?$)/).slice(1);
|
||||
|
||||
// if there is any 2 in the url at all.
|
||||
} else if (path.match(/^(.*?)2(.*?$)/)) {
|
||||
|
||||
// page= is used in django:
|
||||
// http://www.infinite-scroll.com/changelog/comment-page-1/#comment-127
|
||||
if (path.match(/^(.*?page=)2(\/.*|$)/)) {
|
||||
path = path.match(/^(.*?page=)2(\/.*|$)/).slice(1);
|
||||
return path;
|
||||
}
|
||||
|
||||
path = path.match(/^(.*?)2(.*?$)/).slice(1);
|
||||
|
||||
} else {
|
||||
|
||||
// page= is used in drupal too but second page is page=1 not page=2:
|
||||
// thx Jerod Fritz, vladikoff
|
||||
if (path.match(/^(.*?page=)1(\/.*|$)/)) {
|
||||
path = path.match(/^(.*?page=)1(\/.*|$)/).slice(1);
|
||||
return path;
|
||||
} else {
|
||||
debug('Sorry, we couldn\'t parse your Next (Previous Posts) URL. Verify your the css selector points to the correct A tag. If you still get this error: yell, scream, and kindly ask for help at infinite-scroll.com.');
|
||||
props.isInvalidPage = true; //prevent it from running on this page.
|
||||
}
|
||||
}
|
||||
debug('determinePath',path);
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
// Calculate internal height (used for local scroll)
|
||||
function hiddenHeight(element) {
|
||||
var height = 0;
|
||||
$(element).children().each(function () {
|
||||
height = height + $(this).outerHeight(false);
|
||||
});
|
||||
return height;
|
||||
}
|
||||
|
||||
|
||||
//Generate InstanceID based on random data (to give consistent but different ID's)
|
||||
function generateInstanceID(element) {
|
||||
var $element = $(element)
|
||||
var number = $element.length + $element.html().length
|
||||
if($element.attr("class") !== undefined){
|
||||
number += $element.attr("class").length
|
||||
}
|
||||
if($element.attr("id") !== undefined){
|
||||
number += $element.attr("id").length
|
||||
}
|
||||
opts.infid = number;
|
||||
}
|
||||
|
||||
|
||||
// if options is a string, use as a command
|
||||
if (typeof options=='string') {
|
||||
|
||||
var command = options,
|
||||
argument = callback,
|
||||
validCommand = (command == 'pause' || command == 'destroy' || command == 'retrieve' || command == 'binding'),
|
||||
debug = $.fn.infinitescroll._debug;
|
||||
|
||||
argument = argument || null;
|
||||
command = (validCommand) ? $.fn.infinitescroll[command](argument) : debug('Invalid command');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// lets get started.
|
||||
var opts = $.infinitescroll.opts = $.extend({}, $.infinitescroll.defaults, options),
|
||||
props = $.infinitescroll, // shorthand
|
||||
innerContainerHeight, box, frag, desturl, pause, error, errorStatus, method, result;
|
||||
callback = $.fn.infinitescroll._callback = callback || function () { },
|
||||
debug = $.fn.infinitescroll._debug,
|
||||
error = $.fn.infinitescroll._error,
|
||||
pause = $.fn.infinitescroll.pause,
|
||||
destroy = $.fn.infinitescroll.destroy,
|
||||
binding = $.fn.infinitescroll.binding;
|
||||
|
||||
|
||||
// if selectors from opts aren't valid, return false
|
||||
if (!areSelectorsValid(opts)) { return false; }
|
||||
|
||||
|
||||
opts.container = opts.container || document.documentElement;
|
||||
|
||||
|
||||
// contentSelector we'll use for our ajax call
|
||||
opts.contentSelector = opts.contentSelector || this;
|
||||
|
||||
// Generate unique instance ID
|
||||
opts.infid = (opts.infid == 0) ? generateInstanceID(opts.contentSelector) : opts.infid;
|
||||
|
||||
// loadMsgSelector - if we want to place the load message in a specific selector, defaulted to the contentSelector
|
||||
opts.loadMsgSelector = opts.loadMsgSelector || opts.contentSelector;
|
||||
|
||||
|
||||
// get the relative URL - everything past the domain name.
|
||||
var relurl = /(.*?\/\/).*?(\/.*)/,
|
||||
path = $(opts.nextSelector).attr('href');
|
||||
|
||||
if (!path) { debug('Navigation selector not found'); return; }
|
||||
|
||||
// set the path to be a relative URL from root.
|
||||
opts.path = determinePath(path);
|
||||
|
||||
|
||||
// define loading msg
|
||||
props.loadingMsg = $('<div id="infscr-loading" style="text-align: center;"><img alt="Loading..." src="' +
|
||||
|
||||
opts.loadingImg + '" /><div>' + opts.loadingText + '</div></div>');
|
||||
// preload the image
|
||||
(new Image()).src = opts.loadingImg;
|
||||
|
||||
|
||||
//Check if its HTML (window scroll) and set innerContainerHeight
|
||||
opts.binder = (opts.container.nodeName == "HTML") ? $(window) : $(opts.container);
|
||||
innerContainerHeight = (opts.container.nodeName == "HTML") ? $(document).height() : innerContainerHeight = hiddenHeight(opts.container);
|
||||
debug('Scrolling in: ',(opts.container.nodeName == "HTML") ? 'window' : opts.container);
|
||||
|
||||
// distance from nav links to bottom
|
||||
// computed as: height of the document + top offset of container - top offset of nav link
|
||||
opts.pixelsFromNavToBottom = innerContainerHeight +
|
||||
(opts.container == document.documentElement ? 0 : $(opts.container).offset().top) -
|
||||
$(opts.navSelector).offset().top;
|
||||
|
||||
|
||||
// set up our bindings
|
||||
// bind scroll handler to element (if its a local scroll) or window
|
||||
binding('bind');
|
||||
opts.binder.trigger('smartscroll.infscr.' + opts.infid); // trigger the event, in case it's a short page
|
||||
|
||||
return this;
|
||||
|
||||
} // end of $.fn.infinitescroll()
|
||||
|
||||
|
||||
/* Defaults and read-only properties object
|
||||
---------------------------------------------------*/
|
||||
|
||||
$.infinitescroll = {
|
||||
defaults: {
|
||||
debug: false,
|
||||
binder: $(window),
|
||||
preload: false,
|
||||
nextSelector: "div.navigation a:first",
|
||||
loadingImg: "http://www.infinite-scroll.com/loading.gif",
|
||||
loadingText: "<em>Loading the next set of posts...</em>",
|
||||
donetext: "<em>Congratulations, you've reached the end of the internet.</em>",
|
||||
navSelector: "div.navigation",
|
||||
contentSelector: null, // not really a selector. :) it's whatever the method was called on..
|
||||
loadMsgSelector: null,
|
||||
loadingMsgRevealSpeed: 'fast', // controls how fast you want the loading message to come in, ex: 'fast', 'slow', 200 (milliseconds)
|
||||
extraScrollPx: 150,
|
||||
itemSelector: "div.post",
|
||||
animate: false,
|
||||
pathParse: undefined,
|
||||
dataType: 'html',
|
||||
appendCallback: true,
|
||||
bufferPx: 40,
|
||||
orientation: 'height',
|
||||
errorCallback: function () { },
|
||||
currPage: 1,
|
||||
infid: 0, //Instance ID (Generated at setup)
|
||||
isDuringAjax: false,
|
||||
isInvalidPage: false,
|
||||
isDestroyed: false,
|
||||
isDone: false, // for when it goes all the way through the archive.
|
||||
isPaused: false,
|
||||
container: undefined, //If left undefined uses window scroll, set as container for local scroll
|
||||
pixelsFromNavToBottom: undefined,
|
||||
path: undefined
|
||||
},
|
||||
loadingImg: undefined,
|
||||
loadingMsg: undefined,
|
||||
currDOMChunk: null // defined in setup()'s load()
|
||||
};
|
||||
|
||||
|
||||
/* Methods + Commands
|
||||
---------------------------------------------------*/
|
||||
|
||||
// Console log wrapper.
|
||||
$.fn.infinitescroll._debug = function infscr_debug() {
|
||||
if ($.infinitescroll.opts.debug) {
|
||||
return window.console && console.log.call(console, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// shortcut function for...getting shortcuts
|
||||
$.fn.infinitescroll._shorthand = function infscr_shorthand() {
|
||||
|
||||
// someone should write this, and it would rule
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Near Bottom (isNearBottom)
|
||||
$.fn.infinitescroll._nearbottom = function infscr_nearbottom() {
|
||||
|
||||
// replace with shorthand function
|
||||
var opts = $.infinitescroll.opts,
|
||||
debug = $.fn.infinitescroll._debug,
|
||||
hiddenHeight = $.fn.infinitescroll._hiddenheight;
|
||||
|
||||
// distance remaining in the scroll
|
||||
// computed as: document height - distance already scroll - viewport height - buffer
|
||||
|
||||
if (opts.container.nodeName == "HTML") {
|
||||
var pixelsFromWindowBottomToBottom = 0
|
||||
+ $(document).height()
|
||||
// have to do this bs because safari doesnt report a scrollTop on the html element
|
||||
- ($(opts.container).scrollTop() || $(opts.container.ownerDocument.body).scrollTop())
|
||||
- $(window).height();
|
||||
}
|
||||
else {
|
||||
var pixelsFromWindowBottomToBottom = 0
|
||||
+ hiddenHeight(opts.container) - $(opts.container).scrollTop() - $(opts.container).height();
|
||||
|
||||
}
|
||||
|
||||
debug('math:', pixelsFromWindowBottomToBottom, opts.pixelsFromNavToBottom);
|
||||
|
||||
// if distance remaining in the scroll (including buffer) is less than the orignal nav to bottom....
|
||||
return (pixelsFromWindowBottomToBottom - opts.bufferPx < opts.pixelsFromNavToBottom);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Setup function (infscrSetup)
|
||||
$.fn.infinitescroll._setup = function infscr_setup() {
|
||||
|
||||
// replace with shorthand function
|
||||
var props = $.infinitescroll,
|
||||
opts = $.infinitescroll.opts,
|
||||
isNearBottom = $.fn.infinitescroll._nearbottom,
|
||||
kickOffAjax = $.fn.infinitescroll.retrieve;
|
||||
|
||||
if (opts.isDuringAjax || opts.isInvalidPage || opts.isDone || opts.isDestroyed || opts.isPaused) return;
|
||||
|
||||
if (!isNearBottom(opts, props)) return;
|
||||
|
||||
kickOffAjax();
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Ajax function (kickOffAjax)
|
||||
$.fn.infinitescroll.retrieve = function infscr_retrieve() {
|
||||
|
||||
// replace with shorthand function
|
||||
var props = $.infinitescroll,
|
||||
opts = props.opts,
|
||||
debug = $.fn.infinitescroll._debug,
|
||||
loadCallback = $.fn.infinitescroll._loadcallback,
|
||||
error = $.fn.infinitescroll._error,
|
||||
path = opts.path, // get this
|
||||
box, frag, desturl, method, condition;
|
||||
|
||||
|
||||
// we dont want to fire the ajax multiple times
|
||||
opts.isDuringAjax = true;
|
||||
|
||||
|
||||
// show the loading message quickly
|
||||
// then hide the previous/next links after we're
|
||||
// sure the loading message was visible
|
||||
props.loadingMsg.appendTo(opts.loadMsgSelector).show();
|
||||
|
||||
$(opts.navSelector).hide();
|
||||
|
||||
// increment the URL bit. e.g. /page/3/
|
||||
opts.currPage++;
|
||||
|
||||
debug('heading into ajax', path);
|
||||
|
||||
// if we're dealing with a table we can't use DIVs
|
||||
box = $(opts.contentSelector).is('table') ? $('<tbody/>') : $('<div/>');
|
||||
|
||||
|
||||
// INSERT DEBUG ERROR FOR invalid desturl
|
||||
desturl = ($.isFunction(opts.pathParse)) ? opts.pathParse(path.join('2'), opts.currPage) : desturl = path.join(opts.currPage);
|
||||
// desturl = path.join(opts.currPage);
|
||||
|
||||
// create switch parameter for append / callback
|
||||
// MAKE SURE CALLBACK EXISTS???
|
||||
method = (opts.dataType == 'html' || opts.dataType == 'json') ? opts.dataType : 'html+callback';
|
||||
if (opts.appendCallback && opts.dataType == 'html') method += '+callback';
|
||||
|
||||
switch (method) {
|
||||
|
||||
case 'html+callback':
|
||||
|
||||
debug('Using HTML via .load() method');
|
||||
box.load(desturl + ' ' + opts.itemSelector, null, function(jqXHR,textStatus) {
|
||||
loadCallback(box,jqXHR.responseText);
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
case 'html':
|
||||
case 'json':
|
||||
|
||||
debug('Using '+(method.toUpperCase())+' via $.ajax() method');
|
||||
$.ajax({
|
||||
// params
|
||||
url: desturl,
|
||||
dataType: opts.dataType,
|
||||
complete: function _infscrAjax(jqXHR,textStatus) {
|
||||
condition = (typeof(jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === "success" || textStatus === "notmodified");
|
||||
(condition) ? loadCallback(box,jqXHR.responseText) : error([404]);
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Load callback
|
||||
$.fn.infinitescroll._loadcallback = function infscr_loadcallback(box,data) {
|
||||
|
||||
// replace with shorthand function
|
||||
var props = $.infinitescroll,
|
||||
opts = $.infinitescroll.opts,
|
||||
error = $.fn.infinitescroll._error,
|
||||
showDoneMsg = $.fn.infinitescroll._donemsg,
|
||||
callback = $.fn.infinitescroll._callback, // GLOBAL OBJECT FOR CALLBACK
|
||||
result, frag;
|
||||
|
||||
result = (opts.isDone) ? 'done' : (!opts.appendCallback) ? 'no-append' : 'append';
|
||||
|
||||
switch (result) {
|
||||
|
||||
case 'done':
|
||||
|
||||
showDoneMsg();
|
||||
return false;
|
||||
|
||||
break;
|
||||
|
||||
case 'no-append':
|
||||
|
||||
if (opts.dataType == 'html') {
|
||||
data = '<div>'+data+'</div>';
|
||||
data = $(data).find(opts.itemSelector);
|
||||
};
|
||||
|
||||
break;
|
||||
|
||||
case 'append':
|
||||
|
||||
var children = box.children();
|
||||
|
||||
// if it didn't return anything
|
||||
if (children.length == 0 || children.hasClass('error404')) {
|
||||
// trigger a 404 error so we can quit.
|
||||
return error([404]);
|
||||
}
|
||||
|
||||
|
||||
// use a documentFragment because it works when content is going into a table or UL
|
||||
frag = document.createDocumentFragment();
|
||||
while (box[0].firstChild) {
|
||||
frag.appendChild(box[0].firstChild);
|
||||
}
|
||||
|
||||
$(opts.contentSelector)[0].appendChild(frag);
|
||||
// previously, we would pass in the new DOM element as context for the callback
|
||||
// however we're now using a documentfragment, which doesnt havent parents or children,
|
||||
// so the context is the contentContainer guy, and we pass in an array
|
||||
// of the elements collected as the first argument.
|
||||
|
||||
data = children.get();
|
||||
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// fadeout currently makes the <em>'d text ugly in IE6
|
||||
props.loadingMsg.hide();
|
||||
|
||||
|
||||
// smooth scroll to ease in the new content
|
||||
if (opts.animate) {
|
||||
var scrollTo = $(window).scrollTop() + $('#infscr-loading').height() + opts.extraScrollPx + 'px';
|
||||
$('html,body').animate({ scrollTop: scrollTo }, 800, function () { opts.isDuringAjax = false; });
|
||||
}
|
||||
|
||||
if (!opts.animate) opts.isDuringAjax = false; // once the call is done, we can allow it again.
|
||||
|
||||
callback.call($(opts.contentSelector)[0], data);
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Show done message.
|
||||
$.fn.infinitescroll._donemsg = function infscr_donemsg() {
|
||||
|
||||
// replace with shorthand function
|
||||
var props = $.infinitescroll,
|
||||
opts = $.infinitescroll.opts;
|
||||
|
||||
props.loadingMsg
|
||||
.find('img')
|
||||
.hide()
|
||||
.parent()
|
||||
.find('div').html(opts.donetext).animate({ opacity: 1 }, 2000, function () {
|
||||
$(this).parent().fadeOut('normal');
|
||||
});
|
||||
|
||||
// user provided callback when done
|
||||
opts.errorCallback();
|
||||
}
|
||||
|
||||
|
||||
// Pause function
|
||||
$.fn.infinitescroll.pause = function infscr_pause(pause) {
|
||||
|
||||
// if pauseValue is not 'pause' or 'resume', toggle it's value
|
||||
var debug = $.fn.infinitescroll._debug,
|
||||
opts = $.infinitescroll.opts;
|
||||
|
||||
if (pause !== 'pause' && pause !== 'resume' && pause !== 'toggle' && pause !== null) {
|
||||
debug('Invalid argument. Toggling pause value instead');
|
||||
};
|
||||
|
||||
pause = (pause && (pause == 'pause' || pause == 'resume')) ? pause : 'toggle';
|
||||
|
||||
switch (pause) {
|
||||
case 'pause':
|
||||
opts.isPaused = true;
|
||||
break;
|
||||
|
||||
case 'resume':
|
||||
opts.isPaused = false;
|
||||
break;
|
||||
|
||||
case 'toggle':
|
||||
opts.isPaused = !opts.isPaused;
|
||||
break;
|
||||
}
|
||||
|
||||
debug('Paused',opts.isPaused);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Error function
|
||||
$.fn.infinitescroll._error = function infscr_error(xhr) {
|
||||
|
||||
// replace with shorthand function
|
||||
var opts = $.infinitescroll.opts,
|
||||
binder = (opts.container.nodeName == "HTML") ? $(window) : $(opts.container),
|
||||
debug = $.fn.infinitescroll._debug,
|
||||
showDoneMsg = $.fn.infinitescroll._donemsg,
|
||||
error = (!opts.isDone && xhr == 404) ? 'end' : (opts.isDestroyed && xhr == 302) ? 'destroy' : 'unknown';
|
||||
|
||||
switch (error) {
|
||||
|
||||
case 'end':
|
||||
|
||||
// die if we're out of pages.
|
||||
debug('Page not found. Self-destructing...');
|
||||
showDoneMsg();
|
||||
opts.isDone = true;
|
||||
opts.currPage = 1; // if you need to go back to this instance
|
||||
opts.isPaused = false;
|
||||
binder.unbind('smartscroll.infscr.' + opts.infid);
|
||||
|
||||
break;
|
||||
|
||||
case 'destroy':
|
||||
|
||||
// die if destroyed.
|
||||
debug('Destroyed. Going to next instance...');
|
||||
opts.isDone = true;
|
||||
opts.currPage = 1; // if you need to go back to this instance
|
||||
opts.isPaused = false;
|
||||
binder.unbind('smartscroll.infscr.' + opts.infid);
|
||||
|
||||
break;
|
||||
|
||||
case 'unknown':
|
||||
|
||||
// unknown error.
|
||||
debug('Unknown Error. WHAT DID YOU DO?!...');
|
||||
showDoneMsg();
|
||||
opts.isDone = true;
|
||||
opts.currPage = 1; // if you need to go back to this instance
|
||||
binder.unbind('smartscroll.infscr.' + opts.infid);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Destroy current instance of the plugin
|
||||
$.fn.infinitescroll.destroy = function infscr_destroy() {
|
||||
|
||||
// replace with shorthand function
|
||||
var opts = $.infinitescroll.opts,
|
||||
error = $.fn.infinitescroll._error;
|
||||
|
||||
opts.isDestroyed = true;
|
||||
return error([302]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Scroll binding + unbinding
|
||||
$.fn.infinitescroll.binding = function infscr_binding(binding) {
|
||||
|
||||
// replace with shorthand function
|
||||
var opts = $.infinitescroll.opts,
|
||||
setup = $.fn.infinitescroll._setup,
|
||||
error = $.fn.infinitescroll._error,
|
||||
debug = $.fn.infinitescroll._debug;
|
||||
|
||||
switch(binding) {
|
||||
|
||||
case 'bind':
|
||||
opts.binder.bind('smartscroll.infscr.'+opts.infid, setup);
|
||||
break;
|
||||
|
||||
case 'unbind':
|
||||
opts.binder.unbind('smartscroll.infscr.'+opts.infid);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
debug('Binding',binding);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* smartscroll: debounced scroll event for jQuery *
|
||||
* https://github.com/lukeshumard/smartscroll
|
||||
* Based on smartresize by @louis_remi: https://github.com/lrbabe/jquery.smartresize.js *
|
||||
* Copyright 2011 Louis-Remi & Luke Shumard * Licensed under the MIT license. *
|
||||
*/
|
||||
|
||||
var event = $.event,
|
||||
scrollTimeout;
|
||||
|
||||
event.special.smartscroll = {
|
||||
setup: function() {
|
||||
$(this).bind( "scroll", event.special.smartscroll.handler );
|
||||
},
|
||||
teardown: function() {
|
||||
$(this).unbind( "scroll", event.special.smartscroll.handler );
|
||||
},
|
||||
handler: function( event, execAsap ) {
|
||||
// Save the context
|
||||
var context = this,
|
||||
args = arguments;
|
||||
|
||||
// set correct event type
|
||||
event.type = "smartscroll";
|
||||
|
||||
if (scrollTimeout) { clearTimeout(scrollTimeout); }
|
||||
scrollTimeout = setTimeout(function() {
|
||||
jQuery.event.handle.apply( context, args );
|
||||
}, execAsap === "execAsap"? 0 : 100);
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.smartscroll = function( fn ) {
|
||||
return fn ? this.bind( "smartscroll", fn ) : this.trigger( "smartscroll", ["execAsap"] );
|
||||
};
|
||||
|
||||
|
||||
})(jQuery);
|
||||
@@ -1,116 +0,0 @@
|
||||
var KEYCODES = {
|
||||
BACKSPACE : 8,
|
||||
TAB : 9,
|
||||
ENTER : 13,
|
||||
RETURN : 13,
|
||||
SHIFT : 16,
|
||||
CTRL : 17,
|
||||
ALT : 18,
|
||||
PAUSE : 19,
|
||||
BREAK : 19,
|
||||
CAPSLOCK : 20,
|
||||
ESCAPE : 27,
|
||||
ESC : 27,
|
||||
SPACEBAR : 32,
|
||||
PAGEUP : 33,
|
||||
PAGEDOWN : 34,
|
||||
END : 35,
|
||||
HOME : 36,
|
||||
LEFT : 37,
|
||||
UP : 38,
|
||||
RIGHT : 39,
|
||||
DOWN : 40,
|
||||
INSERT : 45,
|
||||
DEL : 46,
|
||||
DELETE : 46,
|
||||
0 : 48,
|
||||
1 : 49,
|
||||
2 : 50,
|
||||
3 : 51,
|
||||
4 : 52,
|
||||
5 : 53,
|
||||
6 : 54,
|
||||
7 : 55,
|
||||
8 : 56,
|
||||
9 : 57,
|
||||
A : 65,
|
||||
B : 66,
|
||||
C : 67,
|
||||
D : 68,
|
||||
E : 69,
|
||||
F : 70,
|
||||
G : 71,
|
||||
H : 72,
|
||||
I : 73,
|
||||
J : 74,
|
||||
K : 75,
|
||||
L : 76,
|
||||
M : 77,
|
||||
N : 78,
|
||||
O : 79,
|
||||
P : 80,
|
||||
Q : 81,
|
||||
R : 82,
|
||||
S : 83,
|
||||
T : 84,
|
||||
U : 85,
|
||||
V : 86,
|
||||
W : 87,
|
||||
X : 88,
|
||||
Y : 89,
|
||||
Z : 90,
|
||||
LEFTWINDOW : 91,
|
||||
RIGHTWINDOW : 92,
|
||||
SELECT : 93,
|
||||
NUMPAD0 : 96,
|
||||
NUMPAD1 : 97,
|
||||
NUMPAD2 : 98,
|
||||
NUMPAD3 : 99,
|
||||
NUMPAD4 : 100,
|
||||
NUMPAD5 : 101,
|
||||
NUMPAD6 : 102,
|
||||
NUMPAD7 : 103,
|
||||
NUMPAD8 : 104,
|
||||
NUMPAD9 : 105,
|
||||
MULTIPLY : 106,
|
||||
ADD : 107,
|
||||
SUBTRACT : 109,
|
||||
DECIMALPOINT : 110,
|
||||
DIVIDE : 111,
|
||||
F1 : 112,
|
||||
F2 : 113,
|
||||
F3 : 114,
|
||||
F4 : 115,
|
||||
F5 : 116,
|
||||
F6 : 117,
|
||||
F7 : 118,
|
||||
F8 : 119,
|
||||
F9 : 120,
|
||||
F10 : 121,
|
||||
F11 : 122,
|
||||
F12 : 123,
|
||||
NUMLOCK : 144,
|
||||
SCROLLLOCK : 145,
|
||||
SEMICOLON : 186,
|
||||
EQUALSIGN : 187,
|
||||
COMMA : 188,
|
||||
DASH : 189,
|
||||
PERIOD : 190,
|
||||
FORWARDSLASH : 191,
|
||||
ACCENTGRAVE : 192,
|
||||
OPENBRACKET : 219,
|
||||
BACKSLASH : 220,
|
||||
CLOSEBRACKET : 221,
|
||||
SINGLEQUOTE : 222,
|
||||
isInsertion : function(keyCode){
|
||||
if(keyCode <= 46 && keyCode != this.RETURN && keyCode != this.SPACEBAR){
|
||||
return false;
|
||||
}else if(keyCode > 90 && keyCode < 96){
|
||||
return false;
|
||||
}else if(keyCode >= 112 && keyCode <= 145){
|
||||
return false;
|
||||
}else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,26 +0,0 @@
|
||||
jQuery.fn.center = function () {
|
||||
this.css("position","absolute");
|
||||
this.css("top", ( $(window).height() - this.height() ) / 2+$(window).scrollTop() + "px");
|
||||
this.css("left", ( $(window).width() - this.width() ) / 2+$(window).scrollLeft() + "px");
|
||||
return this;
|
||||
}
|
||||
|
||||
$(document).ready( function(){
|
||||
var username = $("#user_username"),
|
||||
password = $("#user_password"),
|
||||
forgotPass = $("#forgot_password_link"),
|
||||
controls = $("#controls");
|
||||
|
||||
$("#login").center();
|
||||
$(window).resize(function(){
|
||||
$("#login").center();
|
||||
});
|
||||
|
||||
username.focus();
|
||||
$("form").submit(function(){
|
||||
$('#asterisk').addClass('rideSpinners');
|
||||
forgotPass.addClass('hidden');
|
||||
controls.addClass('hidden');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
var Mentions = {
|
||||
initialize: function(mentionsInput) {
|
||||
return mentionsInput.mentionsInput(Mentions.options);
|
||||
},
|
||||
|
||||
fetchContacts : function(){
|
||||
Mentions.contacts || $.getJSON("/contacts", function(data) {
|
||||
Mentions.contacts = data;
|
||||
});
|
||||
},
|
||||
|
||||
options: {
|
||||
elastic: false,
|
||||
minChars: 1,
|
||||
|
||||
onDataRequest: function(mode, query, callback) {
|
||||
var filteredResults = _.filter(Mentions.contacts, function(item) { return item.name.toLowerCase().indexOf(query.toLowerCase()) > -1 });
|
||||
|
||||
callback.call(this, filteredResults.slice(0,5));
|
||||
},
|
||||
|
||||
templates: {
|
||||
mentionItemSyntax: _.template("@{<%= mention.name %> ; <%= mention.handle %>}")
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,265 +0,0 @@
|
||||
$(document).ready(function(){
|
||||
|
||||
$('.shield a').click(function(){
|
||||
$(this).parents('.shield_wrapper').remove();
|
||||
});
|
||||
var showLoader = function(link){
|
||||
link.addClass('loading');
|
||||
};
|
||||
|
||||
var removeLoader = function(link){
|
||||
link.removeClass('loading')
|
||||
.toggleClass('active')
|
||||
.toggleClass('inactive');
|
||||
};
|
||||
|
||||
/* Heart toggle */
|
||||
$(".like_action", ".stream").bind("tap click", function(evt){
|
||||
evt.preventDefault();
|
||||
var link = $(this),
|
||||
likeCounter = $(this).closest(".stream_element").find("like_count"),
|
||||
href = link.attr("href");
|
||||
|
||||
if(!link.hasClass("loading")){
|
||||
if(link.hasClass('inactive')) {
|
||||
$.ajax({
|
||||
url: href,
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
beforeSend: showLoader(link),
|
||||
success: function(data){
|
||||
removeLoader(link);
|
||||
link.attr("href", href + "/" + data["id"]);
|
||||
|
||||
if(likeCounter){
|
||||
likeCounter.text(parseInt(likeCounter.text) + 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else if(link.hasClass("active")){
|
||||
$.ajax({
|
||||
url: link.attr("href"),
|
||||
dataType: 'json',
|
||||
type: 'DELETE',
|
||||
beforeSend: showLoader(link),
|
||||
complete: function(data){
|
||||
removeLoader(link);
|
||||
link.attr("href", href.replace(/\/\d+$/, ''));
|
||||
|
||||
if(likeCounter){
|
||||
likeCounter.text(parseInt(likeCounter.text) - 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/* Reshare */
|
||||
$(".reshare_action", ".stream").bind("tap click", function(evt){
|
||||
evt.preventDefault();
|
||||
|
||||
var link = $(this),
|
||||
href = link.attr("href"),
|
||||
confirmText = link.attr('title');
|
||||
|
||||
if(!link.hasClass("loading")) {
|
||||
if(link.hasClass('inactive')) {
|
||||
if(confirm(confirmText)) {
|
||||
$.ajax({
|
||||
url: href + "&provider_display_name=mobile",
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
beforeSend: showLoader(link),
|
||||
success: function(data){
|
||||
removeLoader(link);
|
||||
},
|
||||
error: function(data){
|
||||
removeLoader(link);
|
||||
alert("Failed to reshare!");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/* Show comments */
|
||||
$(".show_comments", ".stream").bind("tap click", function(evt){
|
||||
evt.preventDefault();
|
||||
var link = $(this),
|
||||
parent = link.closest(".bottom_bar").first(),
|
||||
commentsContainer = function(){ return parent.find(".comment_container").first(); }
|
||||
existingCommentsContainer = commentsContainer();
|
||||
|
||||
if( link.hasClass('active') ) {
|
||||
existingCommentsContainer.hide();
|
||||
if(!link.hasClass('bottom_collapse')){
|
||||
link.removeClass('active');
|
||||
} else {
|
||||
parent.find(".show_comments").first().removeClass('active');
|
||||
}
|
||||
|
||||
$('html,body').scrollTop(parent.offset().top - parent.closest(".stream_element").height() - 8);
|
||||
|
||||
} else if( existingCommentsContainer.length > 0) {
|
||||
|
||||
if(!existingCommentsContainer.hasClass('noComments')) {
|
||||
$.ajax({
|
||||
url: link.attr('href'),
|
||||
success: function(data){
|
||||
parent.append($(data).find('.comments_container').html());
|
||||
link.addClass('active');
|
||||
existingCommentsContainer.show();
|
||||
scrollToOffset(parent, commentsContainer());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
existingCommentsContainer.show();
|
||||
}
|
||||
|
||||
link.addClass('active');
|
||||
|
||||
} else {
|
||||
$.ajax({
|
||||
url: link.attr('href'),
|
||||
success: function(data){
|
||||
parent.append(data);
|
||||
link.addClass('active');
|
||||
scrollToOffset(parent, commentsContainer());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
var scrollToOffset = function(parent, commentsContainer){
|
||||
var commentCount = commentsContainer.find("li.comment").length;
|
||||
if( commentCount > 3 ) {
|
||||
var lastComment = commentsContainer.find("li:nth-child("+(commentCount-4)+")");
|
||||
$('html,body').animate({
|
||||
scrollTop: lastComment.offset().top
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
$(".stream").delegate("a.comment_action", "tap click", function(evt){
|
||||
evt.preventDefault();
|
||||
var link = $(this);
|
||||
|
||||
if(link.hasClass('inactive')) {
|
||||
var parent = link.closest(".bottom_bar").first(),
|
||||
container = link.closest('.bottom_bar').find('.add_comment_bottom_link_container').first();
|
||||
|
||||
$.ajax({
|
||||
url: link.attr('href'),
|
||||
beforeSend: function(){
|
||||
link.addClass('loading');
|
||||
},
|
||||
context: link,
|
||||
success: function(data){
|
||||
var textarea = function(target) { return target.closest(".stream_element").find('textarea.comment_box').first()[0] };
|
||||
link.removeClass('loading')
|
||||
|
||||
if(!link.hasClass("add_comment_bottom_link")){
|
||||
link.removeClass('inactive');
|
||||
}
|
||||
|
||||
container.hide();
|
||||
parent.append(data);
|
||||
|
||||
console.log($(this).closest(".stream_element").find('textarea'));
|
||||
|
||||
MBP.autogrow(textarea($(this)));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$(".stream").delegate("a.cancel_new_comment", "tap click", function(evt){
|
||||
evt.preventDefault();
|
||||
var link = $(this);
|
||||
form = link.closest("form"),
|
||||
commentActionLink = link.closest(".bottom_bar").find("a.comment_action").first();
|
||||
container = link.closest('.bottom_bar').find('.add_comment_bottom_link_container');
|
||||
|
||||
if(container.length > 0 ){
|
||||
container.first().show();
|
||||
}
|
||||
|
||||
commentActionLink.addClass("inactive");
|
||||
form.remove();
|
||||
});
|
||||
|
||||
$(".new_comment").live("submit", function(evt){
|
||||
evt.preventDefault();
|
||||
var form = $(this);
|
||||
|
||||
$.post(form.attr('action')+"?format=mobile", form.serialize(), function(data){
|
||||
var bottomBar = form.closest('.bottom_bar').first(),
|
||||
container = bottomBar.find('.add_comment_bottom_link_container'),
|
||||
commentActionLink = bottomBar.find("a.comment_action").first();
|
||||
reactionLink = bottomBar.find(".show_comments").first(),
|
||||
commentCount = bottomBar.find(".comment_count");
|
||||
|
||||
if(container.length > 0) {
|
||||
container.before(data);
|
||||
form.remove();
|
||||
container.show();
|
||||
|
||||
} else {
|
||||
var container = $("<div class='comments_container not_all_present'></div>"),
|
||||
comments = $("<ul class='comments'></ul>");
|
||||
|
||||
comments.html(data);
|
||||
container.append(comments);
|
||||
form.remove();
|
||||
container.appendTo(bottomBar)
|
||||
}
|
||||
|
||||
reactionLink.text(reactionLink.text().replace(/(\d+)/, function(match){ return parseInt(match) + 1; }));
|
||||
commentCount.text(commentCount.text().replace(/(\d+)/, function(match){ return parseInt(match) + 1; }));
|
||||
commentActionLink.addClass("inactive");
|
||||
}, 'html');
|
||||
});
|
||||
|
||||
|
||||
$(".service_icon").bind("tap click", function(evt) {
|
||||
var service = $(this).toggleClass("dim"),
|
||||
selectedServices = $("#new_status_message .service_icon:not(.dim)"),
|
||||
provider = service.attr("id"),
|
||||
hiddenField = $("#new_status_message input[name='services[]'][value='" + provider + "']"),
|
||||
publisherMaxChars = 40000,
|
||||
serviceMaxChars;
|
||||
|
||||
|
||||
$("#new_status_message .counter").remove();
|
||||
|
||||
$.each(selectedServices, function() {
|
||||
serviceMaxChars = parseInt($(this).attr("maxchar"));
|
||||
if(publisherMaxChars > serviceMaxChars) {
|
||||
publisherMaxChars = serviceMaxChars;
|
||||
}
|
||||
});
|
||||
|
||||
$('#status_message_text').charCount({allowed: publisherMaxChars, warning: publisherMaxChars/10 });
|
||||
|
||||
if(hiddenField.length > 0) { hiddenField.remove(); }
|
||||
else {
|
||||
$("#new_status_message").append(
|
||||
$("<input/>", {
|
||||
name: "services[]",
|
||||
type: "hidden",
|
||||
value: provider
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
$("#submit_new_message").bind("tap click", function(evt){
|
||||
evt.preventDefault();
|
||||
$("#new_status_message").submit();
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
Diaspora.Pages.AspectsIndex = function() {
|
||||
var self = this;
|
||||
|
||||
this.subscribe("page/ready", function(evt, document) {
|
||||
self.aspectNavigation = self.instantiate("AspectNavigation", document.find("ul#aspect_nav"));
|
||||
});
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
Diaspora.Pages.ContactsIndex = function() {
|
||||
var self = this;
|
||||
|
||||
this.subscribe("page/ready", function(evt, document) {
|
||||
self.infiniteScroll = self.instantiate("InfiniteScroll");
|
||||
$('.conversation_button').twipsy({position: 'below'});
|
||||
});
|
||||
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
Diaspora.Pages.FeaturedUsersIndex = function() {
|
||||
var self = this;
|
||||
|
||||
this.subscribe("page/ready", function(evt, document) {
|
||||
self.infiniteScroll = self.instantiate("InfiniteScroll");
|
||||
});
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
Diaspora.Pages.InvitationsEdit = function() {
|
||||
var self = this;
|
||||
|
||||
this.subscribe("page/ready", function(evt, body) {
|
||||
jQuery.ajaxSetup({'cache': true});
|
||||
$('#user_username').twipsy({trigger: 'select', placement: 'right'});
|
||||
});
|
||||
};
|
||||
@@ -1,12 +0,0 @@
|
||||
Diaspora.Pages.InvitationsNew = function() {
|
||||
var self = this;
|
||||
|
||||
this.subscribe("page/ready", function(evt, document) {
|
||||
var rtl = $('html').attr('dir') == 'rtl',
|
||||
position = rtl ? 'left' : 'right';
|
||||
|
||||
$('#new_user [title]').twipsy({trigger: 'focus', placement: position});
|
||||
$('#user_email').focus();
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
Diaspora.Pages.NotificationsIndex = function() {
|
||||
var self = this;
|
||||
|
||||
this.subscribe("page/ready", function(evt, document) {
|
||||
self.infiniteScroll = self.instantiate("InfiniteScroll");
|
||||
self.instantiate("TimeAgo", document.find("abbr.timeago"));
|
||||
});
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
Diaspora.Pages.ServicesFinder = function() {
|
||||
var self = this;
|
||||
|
||||
this.subscribe("page/ready", function(evt, document) {
|
||||
self.infiniteScroll = self.instantiate("InfiniteScroll");
|
||||
});
|
||||
};
|
||||
@@ -1,81 +0,0 @@
|
||||
Diaspora.Pages.UsersGettingStarted = function() {
|
||||
var self = this;
|
||||
|
||||
this.subscribe("page/ready", function(evt, body) {
|
||||
self.peopleSearch = self.instantiate("Search", body.find("form.people.search_form"));
|
||||
self.tagSearch = self.instantiate("Search", body.find("form.tag_input.search_form"));
|
||||
|
||||
$('#edit_profile').bind('ajax:success', function(evt, data, status, xhr){
|
||||
$('#gs-name-form-spinner').addClass("hidden");
|
||||
$('.profile .saved').show();
|
||||
$('.profile .saved').fadeOut(2000);
|
||||
});
|
||||
|
||||
// It seems that the default behavior of rails ujs is to clear the remote form
|
||||
$('#edit_profile').bind('ajax:complete', function(evt, xhr, status){
|
||||
var firstNameField = $("#profile_first_name");
|
||||
firstNameField.val(firstNameField.data("cachedValue"));
|
||||
|
||||
/* flash message prompt */
|
||||
var message = Diaspora.I18n.t("getting_started.hey", {'name': $("#profile_first_name").val()});
|
||||
Diaspora.page.flashMessages.render({success: true, notice: message});
|
||||
});
|
||||
|
||||
$("#profile_first_name").bind("change", function(){
|
||||
$(this).data("cachedValue", $(this).val());
|
||||
$('#edit_profile').submit();
|
||||
$('#gs-name-form-spinner').removeClass("hidden");
|
||||
});
|
||||
|
||||
$("#profile_first_name").bind("blur", function(){
|
||||
$(this).removeClass("active_input");
|
||||
});
|
||||
|
||||
$("#profile_first_name").bind("focus", function(){
|
||||
$(this).addClass("active_input");
|
||||
});
|
||||
|
||||
$("#awesome_button").bind("click", function(evt){
|
||||
evt.preventDefault();
|
||||
|
||||
var confirmMessage = Diaspora.I18n.t("getting_started.no_tags");
|
||||
|
||||
if(($("#as-selections-tags").find(".as-selection-item").length > 0) || confirm(confirmMessage)) {
|
||||
$('.tag_input').submit();
|
||||
|
||||
/* flash message prompt */
|
||||
var message = Diaspora.I18n.t("getting_started.preparing_your_stream");
|
||||
Diaspora.page.flashMessages.render({success: true, notice: message});
|
||||
} else {
|
||||
/* flash message prompt */
|
||||
var message = Diaspora.I18n.t("getting_started.alright_ill_wait");
|
||||
Diaspora.page.flashMessages.render({success: true, notice: message});
|
||||
}
|
||||
});
|
||||
|
||||
/* ------ */
|
||||
var autocompleteInput = $("#follow_tags");
|
||||
|
||||
autocompleteInput.autoSuggest("/tags", {
|
||||
selectedItemProp: "name",
|
||||
searchObjProps: "name",
|
||||
asHtmlID: "tags",
|
||||
neverSubmit: true,
|
||||
retriveLimit: 10,
|
||||
selectionLimit: false,
|
||||
minChars: 2,
|
||||
keyDelay: 200,
|
||||
startText: "",
|
||||
emptyText: "no_results"
|
||||
});
|
||||
|
||||
autocompleteInput.bind('keydown', function(evt){
|
||||
if(evt.keyCode == 13 || evt.keyCode == 9 || evt.keyCode == 32){
|
||||
evt.preventDefault();
|
||||
if( $('li.as-result-item.active').length == 0 ){
|
||||
$('li.as-result-item').first().click();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -1,72 +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.
|
||||
*/
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
//edit photo
|
||||
$("#edit_photo_toggle").bind('click', function(evt) {
|
||||
evt.preventDefault();
|
||||
$("#photo_edit_options").toggle();
|
||||
$(".edit_photo input:text").first().focus();
|
||||
});
|
||||
|
||||
$('.edit_photo').bind('ajax:loading', function(data, json, xhr) {
|
||||
$("#photo_edit_options").toggle();
|
||||
$("#photo_spinner").show();
|
||||
$("#show_photo").find("img").fadeTo(200,0.3);
|
||||
});
|
||||
|
||||
$('.edit_photo').bind('ajax:failure', function(data, json, xhr) {
|
||||
Diaspora.Alert.show("Failed to delete photo.", "Are you sure you own this?");
|
||||
$("#show_photo").find("img").fadeTo(200,1);
|
||||
$("#photo_spinner").hide();
|
||||
});
|
||||
|
||||
$('.edit_photo').bind('ajax:success', function(data, json, xhr) {
|
||||
json = $.parseJSON(json);
|
||||
$(".edit_photo input:text").val(json.photo.text);
|
||||
$("#caption").html(json.photo.text);
|
||||
$("#show_photo").find("img").fadeTo(200,1);
|
||||
$("#photo_spinner").hide();
|
||||
});
|
||||
|
||||
// make profile photo
|
||||
$('.make_profile_photo').bind('ajax:loading', function(data, json, xhr) {
|
||||
var person_id = $(this).closest(".photo_options").attr('data-actor_person');
|
||||
|
||||
$("img[data-person_id='" + person_id + "']").fadeTo(200, 0.3);
|
||||
});
|
||||
|
||||
$('.make_profile_photo').bind('ajax:success', function(data, json, xhr) {
|
||||
json = $.parseJSON(json);
|
||||
|
||||
$("img[data-person_id='" + json.person_id + "']").fadeTo(200, 1).attr('src', json.image_url_small);
|
||||
});
|
||||
|
||||
$('.make_profile_photo').bind('ajax:failure', function(data, json, xhr) {
|
||||
var person_id = $(this).closest(".photo_options").attr('data-actor_person');
|
||||
Diaspora.Alert.show("Failed to update profile photo!");
|
||||
$("img[data-person_id='" + person_id + "']").fadeTo(200, 1);
|
||||
});
|
||||
|
||||
// right/left hotkeys
|
||||
$(document).keyup(function(e){
|
||||
if(!$(e.target).hasClass('comment_box')){
|
||||
//left
|
||||
if(e.keyCode == 37) {
|
||||
if( $("#photo_show_left").length > 0 ){
|
||||
document.location = $("#photo_show_left").attr('href');
|
||||
}
|
||||
|
||||
//right
|
||||
} else if(e.keyCode == 39) {
|
||||
if( $("#photo_show_right").length > 0 ){
|
||||
document.location = $("#photo_show_right").attr('href');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,221 +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.
|
||||
*/
|
||||
|
||||
//TODO: make this a widget
|
||||
var Publisher = {
|
||||
bookmarklet : false,
|
||||
|
||||
form: function(){
|
||||
return Publisher.cachedForm = Publisher.cachedForm || $('#publisher');
|
||||
},
|
||||
|
||||
input: function(){
|
||||
return Publisher.cachedInput = Publisher.cachedInput || Publisher.form().find('#status_message_fake_text');
|
||||
},
|
||||
|
||||
wrapper: function(){
|
||||
return Publisher.cachedWrapper = Publisher.cachedWrapper || Publisher.form().find('#publisher_textarea_wrapper');
|
||||
},
|
||||
|
||||
hiddenInput: function(){
|
||||
return Publisher.cachedHiddenInput= Publisher.cachedHiddenInput || Publisher.form().find('#status_message_text');
|
||||
},
|
||||
|
||||
submit: function(){
|
||||
return Publisher.cachedSubmit = Publisher.cachedSubmit || Publisher.form().find("input[type='submit']");
|
||||
},
|
||||
|
||||
determineSubmitAvailability: function(){
|
||||
var onlyWhitespaces = ($.trim(Publisher.input().val()) === ''),
|
||||
isSubmitDisabled = Publisher.submit().attr('disabled'),
|
||||
isPhotoAttached = ($("#photodropzone").children().length > 0);
|
||||
|
||||
if ((onlyWhitespaces && !isPhotoAttached) && !isSubmitDisabled) {
|
||||
Publisher.submit().attr('disabled', 'disabled');
|
||||
} else if ((!onlyWhitespaces || isPhotoAttached) && isSubmitDisabled) {
|
||||
Publisher.submit().removeAttr('disabled');
|
||||
}
|
||||
},
|
||||
|
||||
clear: function(){
|
||||
$("#photodropzone").find('li').remove();
|
||||
Publisher.input().mentionsInput("reset");
|
||||
Publisher.wrapper().removeClass("with_attachments");
|
||||
Publisher.hiddenInput().val('');
|
||||
Publisher.determineSubmitAvailability()
|
||||
},
|
||||
|
||||
bindServiceIcons: function(){
|
||||
$(".service_icon").bind("click", function(evt){
|
||||
$(this).toggleClass("dim");
|
||||
Publisher.toggleServiceField($(this));
|
||||
});
|
||||
},
|
||||
|
||||
toggleServiceField: function(service){
|
||||
Publisher.createCounter(service);
|
||||
|
||||
var provider = service.attr('id');
|
||||
var hidden_field = $('#publisher [name="services[]"][value="'+provider+'"]');
|
||||
if(hidden_field.length > 0){
|
||||
hidden_field.remove();
|
||||
} else {
|
||||
$("#publisher .content_creation form").append(
|
||||
'<input id="services_" name="services[]" type="hidden" value="'+provider+'">');
|
||||
}
|
||||
},
|
||||
|
||||
isPublicPost: function(){
|
||||
return $('#publisher [name="aspect_ids[]"]').first().val() == "public";
|
||||
},
|
||||
|
||||
isToAllAspects: function(){
|
||||
return $('#publisher [name="aspect_ids[]"]').first().val() == "all_aspects";
|
||||
},
|
||||
|
||||
selectedAspectIds: function() {
|
||||
var aspects = $('#publisher [name="aspect_ids[]"]');
|
||||
var aspectIds = [];
|
||||
aspects.each(function() { aspectIds.push( parseInt($(this).attr('value'))); });
|
||||
return aspectIds;
|
||||
},
|
||||
|
||||
removeRadioSelection: function(hiddenFields){
|
||||
$.each(hiddenFields, function(index, value){
|
||||
var el = $(value);
|
||||
|
||||
if(el.val() == "all_aspects" || el.val() == "public") {
|
||||
el.remove();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
toggleAspectIds: function(li) {
|
||||
var aspectId = li.attr('data-aspect_id'),
|
||||
hiddenFields = $('#publisher [name="aspect_ids[]"]'),
|
||||
appendId = function(){
|
||||
$("#publisher .content_creation form").append(
|
||||
'<input id="aspect_ids_" name="aspect_ids[]" type="hidden" value="'+aspectId+'">');
|
||||
};
|
||||
|
||||
if(li.hasClass('radio')){
|
||||
$.each(hiddenFields, function(index, value){
|
||||
$(value).remove();
|
||||
});
|
||||
appendId();
|
||||
|
||||
// close dropdown after selecting a binary option
|
||||
li.closest('.dropdown').removeClass('active');
|
||||
|
||||
} else {
|
||||
var hiddenField = $('#publisher [name="aspect_ids[]"][value="'+aspectId+'"]');
|
||||
|
||||
// remove all radio selections
|
||||
Publisher.removeRadioSelection(hiddenFields);
|
||||
|
||||
if(hiddenField.length > 0){
|
||||
hiddenField.remove();
|
||||
} else {
|
||||
appendId();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
createCounter: function(service){
|
||||
var counter = $("#publisher .counter");
|
||||
counter.remove();
|
||||
|
||||
var min = 40000;
|
||||
var a = $('.service_icon:not(.dim)');
|
||||
if(a.length > 0){
|
||||
$.each(a, function(index, value){
|
||||
var num = parseInt($(value).attr('maxchar'));
|
||||
if (min > num) { min = num; }
|
||||
});
|
||||
$('#status_message_fake_text').charCount({allowed: min, warning: min/10 });
|
||||
}
|
||||
},
|
||||
|
||||
bindAspectToggles: function() {
|
||||
$('#publisher .dropdown .dropdown_list li').bind("click", function(evt){
|
||||
var li = $(this),
|
||||
button = li.parent('.dropdown').find('.button');
|
||||
|
||||
if(li.hasClass('radio')){
|
||||
AspectsDropdown.toggleRadio(li);
|
||||
} else {
|
||||
AspectsDropdown.toggleCheckbox(li);
|
||||
}
|
||||
|
||||
AspectsDropdown.updateNumber(li.closest(".dropdown_list"), null, li.parent().find('li.selected').length, '');
|
||||
|
||||
Publisher.toggleAspectIds(li);
|
||||
});
|
||||
},
|
||||
|
||||
textChange : function(){
|
||||
Publisher.determineSubmitAvailability();
|
||||
Publisher.input().mentionsInput("val", function(value) {
|
||||
Publisher.hiddenInput().val(value);
|
||||
});
|
||||
},
|
||||
|
||||
triggerGettingStarted: function(){
|
||||
Publisher.setUpPopovers("#publisher .dropdown", {trigger: 'manual', offset: 10, id: "message_visibility_explain", placement:'below', html:true}, 1000);
|
||||
Publisher.setUpPopovers("#publisher #status_message_fake_text", {trigger: 'manual', placement: 'right', offset: 30, id: "first_message_explain", html:true}, 600);
|
||||
Publisher.setUpPopovers("#gs-shim", {trigger: 'manual', placement: 'left', id:"stream_explain", offset: -5, html:true}, 1400);
|
||||
|
||||
$("#publisher .button.creation").bind("click", function(){
|
||||
$("#publisher .dropdown").popover("hide");
|
||||
$("#publisher #status_message_fake_text").popover("hide");
|
||||
});
|
||||
},
|
||||
|
||||
setUpPopovers: function(selector, options, timeout){
|
||||
var selection = $(selector);
|
||||
selection.popover(options);
|
||||
selection.bind("click", function(){$(this).popover("hide")});
|
||||
|
||||
setTimeout(function(){
|
||||
selection.popover("show");
|
||||
|
||||
var popup = selection.data('popover').$tip[0],
|
||||
closeIcon = $(popup).find(".close");
|
||||
|
||||
closeIcon.bind("click",function(){
|
||||
if($(".popover").length == 1){
|
||||
$.get("/getting_started_completed");
|
||||
};
|
||||
selection.popover("hide");
|
||||
});
|
||||
}, timeout);
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
Publisher.cachedForm = Publisher.cachedSubmit =
|
||||
Publisher.cachedInput = Publisher.cachedHiddenInput = false;
|
||||
|
||||
Publisher.bindServiceIcons();
|
||||
Publisher.bindAspectToggles();
|
||||
|
||||
Mentions.initialize(Publisher.input());
|
||||
|
||||
Publisher.input().bind("focus", function(){
|
||||
Mentions.fetchContacts();
|
||||
})
|
||||
|
||||
if(Publisher.hiddenInput().val() === "") {
|
||||
Publisher.hiddenInput().val(Publisher.input().val());
|
||||
}
|
||||
|
||||
Publisher.input().autoResize({'extraSpace' : 10});
|
||||
Publisher.input().bind('textchange', Publisher.textChange);
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
Publisher.initialize();
|
||||
Diaspora.page.subscribe("stream/reloaded", Publisher.initialize);
|
||||
});
|
||||
@@ -1,404 +0,0 @@
|
||||
/*!
|
||||
* Rails 3 Client Side Validations - v3.1.0
|
||||
* https://github.com/bcardarlela/client_side_validations
|
||||
*
|
||||
* Copyright (c) 2011 Brian Cardarella
|
||||
* Licensed under the MIT license
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
$.fn.validate = function() {
|
||||
return this.filter('form[data-validate]').each(function() {
|
||||
var form = $(this);
|
||||
var settings = window[form.attr('id')];
|
||||
|
||||
// Set up the events for the form
|
||||
form
|
||||
.submit(function() { return form.isValid(settings.validators); })
|
||||
.bind('ajax:beforeSend', function() { return form.isValid(settings.validators); })
|
||||
// Callbacks
|
||||
.bind('form:validate:after', function(eventData) { clientSideValidations.callbacks.form.after( form, eventData); })
|
||||
.bind('form:validate:before', function(eventData) { clientSideValidations.callbacks.form.before(form, eventData); })
|
||||
.bind('form:validate:fail', function(eventData) { clientSideValidations.callbacks.form.fail( form, eventData); })
|
||||
.bind('form:validate:pass', function(eventData) { clientSideValidations.callbacks.form.pass( form, eventData); })
|
||||
|
||||
// Set up the events for each validatable form element
|
||||
.find('[data-validate]:input:not(:radio)')
|
||||
.live('focusout', function() { $(this).isValid(settings.validators); })
|
||||
.live('change', function() { $(this).data('changed', true); })
|
||||
// Callbacks
|
||||
.live('element:validate:after', function(eventData) { clientSideValidations.callbacks.element.after( $(this), eventData); })
|
||||
.live('element:validate:before', function(eventData) { clientSideValidations.callbacks.element.before($(this), eventData); })
|
||||
.live('element:validate:fail', function(eventData, message) {
|
||||
var element = $(this);
|
||||
clientSideValidations.callbacks.element.fail(element, message, function() {
|
||||
addError(element, message);
|
||||
}, eventData) })
|
||||
.live('element:validate:pass', function(eventData) {
|
||||
var element = $(this);
|
||||
clientSideValidations.callbacks.element.pass(element, function() {
|
||||
removeError(element);
|
||||
}, eventData) })
|
||||
// Checkboxes - Live events don't support filter
|
||||
.end().find('[data-validate]:checkbox')
|
||||
.live('click', function() { $(this).isValid(settings.validators); })
|
||||
// Inputs for confirmations
|
||||
.end().find('[id*=_confirmation]').each(function() {
|
||||
var confirmationElement = $(this),
|
||||
element = form.find('#' + this.id.match(/(.+)_confirmation/)[1] + '[data-validate]:input');
|
||||
|
||||
if (element[0]) {
|
||||
$('#' + confirmationElement.attr('id'))
|
||||
.live('focusout', function() {
|
||||
element.data('changed', true).isValid(settings.validators);
|
||||
})
|
||||
.live('keyup', function() {
|
||||
element.data('changed', true).isValid(settings.validators);
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
var addError = function(element, message) {
|
||||
clientSideValidations.formBuilders[settings.type].add(element, settings, message);
|
||||
}
|
||||
|
||||
var removeError = function(element) {
|
||||
clientSideValidations.formBuilders[settings.type].remove(element, settings);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$.fn.isValid = function(validators) {
|
||||
if ($(this[0]).is('form')) {
|
||||
return validateForm($(this[0]), validators);
|
||||
} else {
|
||||
return validateElement($(this[0]), validators[this[0].name]);
|
||||
}
|
||||
}
|
||||
|
||||
var validateForm = function(form, validators) {
|
||||
var valid = true;
|
||||
|
||||
form.trigger('form:validate:before').find('[data-validate]:input').each(function() {
|
||||
if (!$(this).isValid(validators)) { valid = false; }
|
||||
});
|
||||
|
||||
if (valid) {
|
||||
form.trigger('form:validate:pass');
|
||||
} else {
|
||||
form.trigger('form:validate:fail');
|
||||
}
|
||||
|
||||
form.trigger('form:validate:after');
|
||||
return valid;
|
||||
}
|
||||
|
||||
var validateElement = function(element, validators) {
|
||||
element.trigger('element:validate:before');
|
||||
|
||||
if (element.data('changed') !== false) {
|
||||
var valid = true;
|
||||
element.data('changed', false);
|
||||
|
||||
// Because 'length' is defined on the list of validators we cannot call jQuery.each on
|
||||
// the clientSideValidations.validators.all() object
|
||||
for (kind in clientSideValidations.validators.all()) {
|
||||
if (validators[kind] && (message = clientSideValidations.validators.all()[kind](element, validators[kind]))) {
|
||||
element.trigger('element:validate:fail', message).data('valid', false);
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid) { element.data('valid', null); element.trigger('element:validate:pass'); }
|
||||
}
|
||||
|
||||
element.trigger('element:validate:after');
|
||||
return element.data('valid') === false ? false : true;
|
||||
}
|
||||
|
||||
// Main hook
|
||||
// If new forms are dynamically introduced into the DOM the .validate() method
|
||||
// must be invoked on that form
|
||||
$(function() { $('form[data-validate]').validate(); })
|
||||
})(jQuery);
|
||||
|
||||
var clientSideValidations = {
|
||||
validators: {
|
||||
all: function() { return jQuery.extend({}, clientSideValidations.validators.local, clientSideValidations.validators.remote) },
|
||||
local: {
|
||||
presence: function(element, options) {
|
||||
if (/^\s*$/.test(element.val() || "")) {
|
||||
return options.message;
|
||||
}
|
||||
},
|
||||
acceptance: function(element, options) {
|
||||
switch (element.attr('type')) {
|
||||
case 'checkbox':
|
||||
if (!element.attr('checked')) {
|
||||
return options.message;
|
||||
}
|
||||
break;
|
||||
case 'text':
|
||||
if (element.val() != (options.accept || '1')) {
|
||||
return options.message;
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
format: function(element, options) {
|
||||
if ((message = this.presence(element, options)) && options.allow_blank == true) {
|
||||
return;
|
||||
} else if (message) {
|
||||
return message;
|
||||
} else {
|
||||
if (options['with'] && !options['with'].test(element.val())) {
|
||||
return options.message;
|
||||
} else if (options['without'] && options['without'].test(element.val())) {
|
||||
return options.message;
|
||||
}
|
||||
}
|
||||
},
|
||||
numericality: function(element, options) {
|
||||
if (!/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d*)?$/.test(element.val())) {
|
||||
return options.messages.numericality;
|
||||
}
|
||||
|
||||
if (options.only_integer && !/^\d+$/.test(element.val())) {
|
||||
return options.messages.only_integer;
|
||||
}
|
||||
|
||||
var CHECKS = { greater_than: '>', greater_than_or_equal_to: '>=',
|
||||
equal_to: '==', less_than: '<', less_than_or_equal_to: '<=' }
|
||||
|
||||
for (var check in CHECKS) {
|
||||
if (options[check] != undefined && !(new Function("return " + element.val() + CHECKS[check] + options[check])())) {
|
||||
return options.messages[check];
|
||||
}
|
||||
}
|
||||
|
||||
if (options.odd && !(parseInt(element.val()) % 2)) {
|
||||
return options.messages.odd;
|
||||
}
|
||||
|
||||
if (options.even && (parseInt(element.val()) % 2)) {
|
||||
return options.messages.even;
|
||||
}
|
||||
},
|
||||
length: function(element, options) {
|
||||
var blankOptions = {};
|
||||
if (options.is) {
|
||||
blankOptions.message = options.messages.is;
|
||||
} else if (options.minimum) {
|
||||
blankOptions.message = options.messages.minimum;
|
||||
}
|
||||
if ((message = this.presence(element, blankOptions)) && options.allow_blank == true) {
|
||||
return;
|
||||
} else if (message) {
|
||||
return message;
|
||||
} else {
|
||||
var CHECKS = { is: '==', minimum: '>=', maximum: '<=' }
|
||||
var tokenizer = options.js_tokenizer || "split('')";
|
||||
var tokenized_length = new Function("element", "return (element.val()." + tokenizer + " || '').length;")(element);
|
||||
|
||||
for (var check in CHECKS) {
|
||||
if (options[check] && !(new Function("return " + tokenized_length + CHECKS[check] + options[check])())) {
|
||||
return options.messages[check];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
exclusion: function(element, options) {
|
||||
if ((message = this.presence(element, options)) && options.allow_blank == true) {
|
||||
return;
|
||||
} else if (message) {
|
||||
return message;
|
||||
} else {
|
||||
if (options['in']) {
|
||||
for (var i = 0; i < options['in'].length; i++) {
|
||||
if (options['in'][i] == element.val()) {
|
||||
return options.message;
|
||||
}
|
||||
}
|
||||
} else if (options['range']) {
|
||||
var lower = options['range'][0],
|
||||
upper = options['range'][1];
|
||||
if (element.val() >= lower && element.val() <= upper) {
|
||||
return options.message;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
inclusion: function(element, options) {
|
||||
if ((message = this.presence(element, options)) && options.allow_blank == true) {
|
||||
return;
|
||||
} else if (message) {
|
||||
return message;
|
||||
} else {
|
||||
if (options['in']) {
|
||||
for (var i = 0; i < options['in'].length; i++) {
|
||||
if (options['in'][i] == element.val()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return options.message;
|
||||
} else if (options['range']) {
|
||||
var lower = options['range'][0],
|
||||
upper = options['range'][1];
|
||||
|
||||
if (element.val() >= lower && element.val() <= upper) {
|
||||
return;
|
||||
} else {
|
||||
return options.message;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmation: function(element, options) {
|
||||
if (element.val() != jQuery('#' + element.attr('id') + '_confirmation').val()) {
|
||||
return options.message;
|
||||
}
|
||||
}
|
||||
},
|
||||
remote: {
|
||||
uniqueness: function(element, options) {
|
||||
var data = {};
|
||||
data['case_sensitive'] = !!options.case_sensitive;
|
||||
if (options.id) {
|
||||
data['id'] = options.id;
|
||||
}
|
||||
|
||||
if (options.scope) {
|
||||
data.scope = {}
|
||||
for (key in options.scope) {
|
||||
var scoped_element = jQuery('[name="' + element.attr('name').replace(/\[\w+]$/, '[' + key + ']' + '"]'));
|
||||
if (scoped_element[0] && scoped_element.val() != options.scope[key]) {
|
||||
data.scope[key] = scoped_element.val();
|
||||
scoped_element.unbind('change.' + element.id).bind('change.' + element.id, function() { element.trigger('change'); element.trigger('focusout'); });
|
||||
} else {
|
||||
data.scope[key] = options.scope[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Kind of a hack but this will isolate the resource name and attribute.
|
||||
// e.g. user[records_attributes][0][title] => records[title]
|
||||
// e.g. user[record_attributes][title] => record[title]
|
||||
// Server side handles classifying the resource properly
|
||||
if (/_attributes]/.test(element.attr('name'))) {
|
||||
var name = element.attr('name').match(/\[\w+_attributes]/g).pop().match(/\[(\w+)_attributes]/).pop();
|
||||
name += /(\[\w+])$/.exec(element.attr('name'))[1];
|
||||
} else {
|
||||
var name = element.attr('name');
|
||||
}
|
||||
|
||||
// Override the name if a nested module class is passed
|
||||
if (options['class']) {
|
||||
name = options['class'] + '[' + name.split('[')[1]
|
||||
}
|
||||
data[name] = element.val();
|
||||
|
||||
if (jQuery.ajax({
|
||||
url: '/validators/uniqueness',
|
||||
data: data,
|
||||
async: false
|
||||
}).status == 200) {
|
||||
return options.message;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
formBuilders: {
|
||||
'ActionView::Helpers::FormBuilder': {
|
||||
add: function(element, settings, message) {
|
||||
if (element.data('valid') !== false && jQuery('label.message[for="' + element.attr('id') + '"]')[0] == undefined) {
|
||||
var inputErrorField = jQuery(settings.input_tag),
|
||||
labelErrorField = jQuery(settings.label_tag),
|
||||
label = jQuery('label[for="' + element.attr('id') + '"]:not(.message)');
|
||||
|
||||
if (element.attr('autofocus')) { element.attr('autofocus', false) };
|
||||
element.before(inputErrorField);
|
||||
inputErrorField.find('span#input_tag').replaceWith(element);
|
||||
inputErrorField.find('label.message').attr('for', element.attr('id'));
|
||||
labelErrorField.find('label.message').attr('for', element.attr('id'));
|
||||
label.replaceWith(labelErrorField);
|
||||
labelErrorField.find('label#label_tag').replaceWith(label);
|
||||
}
|
||||
jQuery('label.message[for="' + element.attr('id') + '"]').text(message);
|
||||
},
|
||||
remove: function(element, settings) {
|
||||
var errorFieldClass = jQuery(settings.input_tag).attr('class'),
|
||||
inputErrorField = element.closest('.' + errorFieldClass),
|
||||
label = jQuery('label[for="' + element.attr('id') + '"]:not(.message)'),
|
||||
labelErrorField = label.closest('.' + errorFieldClass);
|
||||
|
||||
if (inputErrorField[0]) {
|
||||
inputErrorField.find('#' + element.attr('id')).detach();
|
||||
inputErrorField.replaceWith(element);
|
||||
label.detach();
|
||||
labelErrorField.replaceWith(label);
|
||||
}
|
||||
}
|
||||
},
|
||||
'SimpleForm::FormBuilder': {
|
||||
add: function(element, settings, message) {
|
||||
if (element.data('valid') !== false) {
|
||||
var wrapper = element.closest(settings.wrapper_tag);
|
||||
wrapper.addClass(settings.wrapper_error_class);
|
||||
var errorElement = $('<' + settings.error_tag + ' class="' + settings.error_class + '">' + message + '</' + settings.error_tag + '>');
|
||||
wrapper.append(errorElement);
|
||||
} else {
|
||||
element.parent().find(settings.error_tag + '.' + settings.error_class).text(message);
|
||||
}
|
||||
},
|
||||
remove: function(element, settings) {
|
||||
var wrapper = element.closest(settings.wrapper_tag + '.' + settings.wrapper_error_class);
|
||||
wrapper.removeClass(settings.wrapper_error_class);
|
||||
var errorElement = wrapper.find(settings.error_tag + '.' + settings.error_class);
|
||||
errorElement.remove();
|
||||
}
|
||||
|
||||
},
|
||||
'Formtastic::FormBuilder': {
|
||||
add: function(element, settings, message) {
|
||||
if (element.data('valid') !== false) {
|
||||
var wrapper = element.closest('li');
|
||||
wrapper.addClass('error');
|
||||
var errorElement = $('<p class="' + settings.inline_error_class + '">' + message + '</p>');
|
||||
wrapper.append(errorElement);
|
||||
} else {
|
||||
element.parent().find('p.' + settings.inline_error_class).text(message);
|
||||
}
|
||||
},
|
||||
remove: function(element, settings) {
|
||||
var wrapper = element.closest('li.error');
|
||||
wrapper.removeClass('error');
|
||||
var errorElement = wrapper.find('p.' + settings.inline_error_class);
|
||||
errorElement.remove();
|
||||
}
|
||||
},
|
||||
'NestedForm::Builder': {
|
||||
add: function(element, settings, message) {
|
||||
clientSideValidations.formBuilders['ActionView::Helpers::FormBuilder'].add(element, settings, message);
|
||||
},
|
||||
remove: function(element, settings, message) {
|
||||
clientSideValidations.formBuilders['ActionView::Helpers::FormBuilder'].remove(element, settings, message);
|
||||
}
|
||||
}
|
||||
},
|
||||
callbacks: {
|
||||
element: {
|
||||
after: function(element, eventData) { },
|
||||
before: function(element, eventData) { },
|
||||
fail: function(element, message, addError, eventData) { addError() },
|
||||
pass: function(element, removeError, eventData) { removeError() }
|
||||
},
|
||||
form: {
|
||||
after: function(form, eventData) { },
|
||||
before: function(form, eventData) { },
|
||||
fail: function(form, eventData) { },
|
||||
pass: function(form, eventData) { }
|
||||
}
|
||||
}
|
||||
};
|
||||
1158
public/javascripts/vendor/backbone.js
vendored
1158
public/javascripts/vendor/backbone.js
vendored
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user