Merge branch 'master' of git://github.com/diaspora/diaspora

This commit is contained in:
Jordi Mallach 2012-01-31 01:13:56 +01:00
commit 67e907eef0
30 changed files with 4012 additions and 657 deletions

View file

@ -15,7 +15,7 @@ class CommentsController < ApplicationController
end
def create
target = current_user.find_visible_shareable_by_id Post, params[:post_id]
target = current_user.find_visible_shareable_by_id(Post, params[:post_id])
text = params[:text]
if target
@ -24,7 +24,7 @@ class CommentsController < ApplicationController
if @comment.save
Rails.logger.info("event => :create, :type => :comment, :user => #{current_user.diaspora_handle},
:status => :success, :comment => #{@comment.id}, :chars => #{params[:text].length}")
Postzord::Dispatcher.build(current_user, @comment).post
current_user.dispatch_post(@comment)
respond_to do |format|
format.json{ render :json => @comment.as_api_response(:backbone), :status => 201 }
@ -51,8 +51,7 @@ class CommentsController < ApplicationController
else
respond_to do |format|
format.mobile {redirect_to :back}
format.js {render :nothing => true, :status => 403}
format.json { render :nothing => true, :status => 403 }
format.any(:js, :json) {render :nothing => true, :status => 403}
end
end
end

View file

@ -6,6 +6,7 @@ require File.join(Rails.root, "lib", 'stream', "person")
class PeopleController < ApplicationController
before_filter :authenticate_user!, :except => [:show]
before_filter :redirect_if_tag_search, :only => [:index]
respond_to :html, :except => [:tag_index]
respond_to :json, :only => [:index, :show]
@ -15,50 +16,27 @@ class PeopleController < ApplicationController
render :file => "#{Rails.root}/public/404.html", :layout => false, :status => 404
end
helper_method :search_query
def index
@aspect = :search
params[:q] ||= params[:term] || ''
if params[:q][0] == 35 || params[:q][0] == '#'
if params[:q].length > 1
tag_name = params[:q].gsub(/[#\.]/, '')
redirect_to tag_path(:name => tag_name, :q => params[:q])
return
else
flash[:error] = I18n.t('tags.show.none', :name => params[:q])
redirect_to :back
end
end
limit = params[:limit] ? params[:limit].to_i : 15
@people = Person.search(search_query, current_user)
respond_to do |format|
format.json do
@people = Person.search(params[:q], current_user).limit(limit)
@people = @people.limit(limit)
render :json => @people
end
format.html do
format.any(:html, :mobile) do
#only do it if it is an email address
if diaspora_id?(params[:q])
people = Person.where(:diaspora_handle => params[:q].downcase)
Webfinger.in_background(params[:q]) if people.empty?
else
people = Person.search(params[:q], current_user)
if diaspora_id?(search_query)
@people = Person.where(:diaspora_handle => search_query.downcase)
Webfinger.in_background(search_query) if @people.empty?
end
@normalized_tag_for_query = ActsAsTaggableOn::Tag.normalize(params[:q])
@people = people.paginate( :page => params[:page], :per_page => 15)
@hashes = hashes_for_people(@people, @aspects)
end
format.mobile do
#only do it if it is an email address
if diaspora_id?(params[:q])
people = Person.where(:diaspora_handle => params[:q])
Webfinger.in_background(params[:q]) if people.empty?
else
people = Person.search(params[:q], current_user)
end
@people = people.paginate( :page => params[:page], :per_page => 15)
@people = @people.paginate(:page => params[:page], :per_page => 15)
@hashes = hashes_for_people(@people, @aspects)
end
end
@ -70,7 +48,7 @@ class PeopleController < ApplicationController
respond_with @people
end
def hashes_for_people people, aspects
def hashes_for_people(people, aspects)
ids = people.map{|p| p.id}
contacts = {}
Contact.unscoped.where(:user_id => current_user.id, :person_id => ids).each do |contact|
@ -168,6 +146,21 @@ class PeopleController < ApplicationController
!query.try(:match, /^(\w)*@([a-zA-Z0-9]|[-]|[.]|[:])*$/).nil?
end
def search_query
@search_query ||= params[:q] || params[:term] || ''
end
def redirect_if_tag_search
if search_query.starts_with?('#')
if search_query.length > 1
redirect_to tag_path(:name => search_query.delete('#.'), :q => search_query)
else
flash[:error] = I18n.t('tags.show.none', :name => search_query)
redirect_to :back
end
end
end
private
def remote_profile_with_no_user_session?

View file

@ -16,13 +16,12 @@ class PostsController < ApplicationController
if user_signed_in?
@post = current_user.find_visible_shareable_by_id(Post, params[:id], :key => key)
@commenting_disabled = user_can_not_comment_on_post?
else
@post = Post.where(key => params[:id], :public => true).includes(:author, :comments => :author).first
@commenting_disabled = true
end
if @post
@commenting_disabled = can_not_comment_on_post?
# mark corresponding notification as read
if user_signed_in? && notification = Notification.where(:recipient_id => current_user.id, :target_id => @post.id).first
notification.unread = false
@ -65,8 +64,10 @@ class PostsController < ApplicationController
request.format = :html if request.format == 'application/html+xml'
end
def user_can_not_comment_on_post?
if @post.public && @post.author.local?
def can_not_comment_on_post?
if !user_signed_in?
true
elsif @post.public && @post.author.local?
false
elsif current_user.contact_for(@post.author)
false

View file

@ -4,6 +4,18 @@
module PeopleHelper
include ERB::Util
def search_header
if search_query.blank?
content_tag(:h2, t('people.index.no_results'))
else
content_tag(:h2, :id => 'search_title') do
t('people.index.results_for').html_safe + ' ' +
content_tag(:span, search_query, :class => 'term')
end
end
end
def request_partial single_aspect_form
if single_aspect_form
'requests/new_request_with_aspect_to_person'
@ -13,8 +25,8 @@ module PeopleHelper
end
def search_or_index
if params[:q]
I18n.t 'people.helper.results_for',:params => params[:q]
if search_query
I18n.t 'people.helper.results_for',:params => search_query
else
I18n.t "people.helper.people_on_pod_are_aware_of"
end

View file

@ -0,0 +1,19 @@
module TagsHelper
def looking_for_tag_link
return if search_query.include?('@') || normalized_tag_name.blank?
content_tag('h4') do
content_tag('small') do
t('people.index.looking_for', :tag_link => tag_link).html_safe
end
end
end
def normalized_tag_name
ActsAsTaggableOn::Tag.normalize(search_query)
end
def tag_link
tag = normalized_tag_name
link_to("##{tag}", tag_path(:name => tag))
end
end

View file

@ -3,10 +3,9 @@
-# the COPYRIGHT file.
= form_tag( post_comments_path(post_id), :id => "new_comment_on_#{post_id}", :class => 'new_comment', :autocomplete => "off") do
= hidden_field_tag :post_id, post_id, :id => "post_id_on_#{post_id}"
= text_area_tag :text, nil, :class => "comment_box",:id => "comment_text_on_#{post_id}", :placeholder => t('.comment'), :autofocus => true
%fieldset
= hidden_field_tag :post_id, post_id, :id => "post_id_on_#{post_id}"
= text_area_tag :text, nil, :class => "span12 comment_box", :id => "comment_text_on_#{post_id}", :placeholder => t('.comment'), :autofocus => true
.actions
= link_to "Cancel", post_path(post_id), :class => "cancel_new_comment btn"
= submit_tag t('.comment'), :id => "comment_submit_#{post_id}", :disable_with => t('.commenting'), :class => "action"
= submit_tag t('.comment'), :id => "comment_submit_#{post_id}", :disable_with => t('.commenting'), :class => "btn primary"

View file

@ -59,10 +59,10 @@
= t('.no_contacts')
%br
%br
= t('.check_out')
= link_to t('contacts.spotlight.community_spotlight'), community_spotlight_path
- if @aspect
or
= link_to t('.add_to_aspect', :name => @aspect.name), edit_aspect_path(@aspect), :rel => "facebox"
!= t('.no_contacts_message_with_aspect',
:community_spotlight => link_to(t('.community_spotlight'), community_spotlight_path),
:add_to_aspect_link => link_to(t('.add_to_aspect_link', :name => @aspect.name), edit_aspect_path(@aspect), :rel => "facebox"))
- else
!= t('.no_contacts_message',
:community_spotlight => link_to(t('.community_spotlight'), community_spotlight_path))

View file

@ -46,17 +46,21 @@
= yield(:head)
%body
#main{:role => "main"}
= yield
.navbar.navbar-fixed-top
.navbar-inner
.container{:style => "position: relative;"}
= link_to(image_tag('header-logo2x.png', :height => 40, :width => 40, :id => 'header_title'), multi_stream_path)
%header
= link_to(image_tag('header-logo2x.png', :height => 40, :width => 40, :id => 'header_title'), multi_stream_path)
- if user_signed_in?
.right
- if yield(:header_action).present?
= yield(:header_action)
- else
= link_to(image_tag('icons/compose_mobile2.png', :class => 'compose_icon'), new_status_message_path)
- if user_signed_in?
- if yield(:header_action).present?
= yield(:header_action)
- else
= link_to(image_tag('icons/compose_mobile2.png', :height => 28, :width => 28), new_status_message_path, :class => 'compose_icon')
#main.container{:role => "main"}
.row
= yield
- if user_signed_in?
= render :partial =>'shared/footer'

View file

@ -2,17 +2,17 @@
-# licensed under the Affero General Public License version 3 or later. See
-# the COPYRIGHT file.
%h2{:style => "padding:0 10px;display:none;"}
- if @stream.for_all_aspects?
= t('all_aspects')
- else
= @stream.aspect
#main_stream.stream
= render 'shared/stream', :posts => @stream.stream_posts
-if @stream.stream_posts.length > 0
#pagination
%a.more-link.paginate{:href => next_page_path}
%h1
= t("more")
.span12
%h2{:style => "padding:0 10px;display:none;"}
- if @stream.for_all_aspects?
= t('all_aspects')
- else
= @stream.aspect
#main_stream.stream
= render 'shared/stream', :posts => @stream.stream_posts
-if @stream.stream_posts.length > 0
#pagination
%a.more-link.paginate{:href => next_page_path}
%h1
= t("more")

View file

@ -10,18 +10,8 @@
= javascript_include_tag 'contact-list'
.span-24.last
- if params[:q].blank?
%h2
=t('.no_results')
- else
%h2#search_title
=t('.results_for')
%span.term
= params[:q]
- if @normalized_tag_for_query.present?
%h4
%small
= t('.looking_for', :tag_link => link_to("##{@normalized_tag_for_query}", tag_path(:name => @normalized_tag_for_query))).html_safe
= search_header
= looking_for_tag_link
.span-15
%hr
.clearfix

View file

@ -6,32 +6,35 @@
%h1
DIASPORA*
#author_info.profile
= person_image_tag @person, :thumb_medium
%h2
= @person.name
%span.description
= @person.diaspora_handle
.span12
#author_info
= person_image_tag @person, :thumb_medium
.content
%h2
= @person.name
%span.description
= @person.diaspora_handle
- if user_signed_in? && !(@contact.persisted? || current_user.person == @person)
- if @incoming_request
.floating
%h3
= t('.incoming_request', :name => @person.name)
%h4
= link_to t('.return_to_aspects'), aspects_manage_path
= t('.to_accept_or_ignore')
- if user_signed_in? && !(@contact.persisted? || current_user.person == @person)
- if @incoming_request
.floating
%h3
= t('.incoming_request', :name => @person.name)
%h4
= link_to t('.return_to_aspects'), aspects_manage_path
= t('.to_accept_or_ignore')
- if @stream.stream_posts.length > 0
-if @post_type == :photos
= render 'photos/index', :photos => @stream.stream_posts
.span12
- if @stream.stream_posts.length > 0
-if @post_type == :photos
= render 'photos/index', :photos => @stream.stream_posts
- else
#main_stream.stream
= render 'shared/stream', :posts => @stream.stream_posts
#pagination
=link_to(t('more'), next_page_path, :class => 'paginate')
- else
#main_stream.stream
= render 'shared/stream', :posts => @stream.stream_posts
#pagination
=link_to(t('more'), next_page_path, :class => 'paginate')
- else
#main_stream
%div{:style=>"text-align:center;", :class => "dull"}
= t('.has_not_shared_with_you_yet', :name => @person.first_name)
#main_stream
%div{:style=>"text-align:center;", :class => "dull"}
= t('.has_not_shared_with_you_yet', :name => @person.first_name)

View file

@ -2,28 +2,32 @@
-# licensed under the Affero General Public License version 3 or later. See
-# the COPYRIGHT file.
.stream
#main_stream.stream
#login_form
.login-container
%h2
Log in
= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f|
.row
.row
= f.label :username, t('username')
.centered
= f.text_field :username
.row
.row
= f.label :password , t('password')
.centered
= f.password_field :password
.row
= hidden_field(:user, :remember_me, :value => 1)
= f.submit t('devise.sessions.new.sign_in'), :class => 'login-submit'
- if display_password_reset_link?
= link_to "Forgot password?", new_password_path(resource_name)
= form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => {:class => 'form-horizontal'}) do |f|
%fieldset
%legend
Log in
.control-group
= f.label :username, t('username'), :class => "control-label"
.controls
= f.text_field :username
.control-group
= f.label :password , t('password'), :class => "control-label"
.controls
= f.password_field :password
= hidden_field(:user, :remember_me, :value => 1)
.controls
= f.submit t('devise.sessions.new.sign_in'), :class => 'btn primary'
%footer
- if display_password_reset_link?
= link_to "Forgot Password?", new_password_path(resource_name)
- if display_registration_link?
= link_to t('.sign_up'), new_registration_path(resource_name)

View file

@ -1,6 +1,11 @@
%form{:action => "https://diaspora-project-site.heroku.com/donate", :method => "get"}
%select{:name => "monthly_amount"}
%option{:value => "1"} Supporter : $5.00USD
%option{:value => "2"} Member : $10.00USD
%option{:value => "3"} Freedom Fighter : $20.00USD
%form{:action => "https://www.paypal.com/cgi-bin/webscr", :method => "post"}
%input{:name => "cmd", :type => "hidden", :value => "_s-xclick"}
%input{:name => "hosted_button_id", :type => "hidden", :value => AppConfig[:paypal_hosted_button_id]}
%input{:name => "on0", :type => "hidden", :value => "Type"}
%input{:name => "modify", :type => "hidden", :value => "2"}
%select{:name => "os0"}
%option{:value => "Mocha"} Mocha : $3.00USD
%option{:value => "Americano"} Americano : $5.00USD
%option{:value => "Box o' Joe"} Box o' Joe : $20.00USD
%input{:name => "currency_code", :type => "hidden", :value => "USD"}
%input{:name => "submit", :type => "submit", :value => t('aspects.index.donate')}

View file

@ -20,4 +20,3 @@
= t('public')
- else
= t('limited')

View file

@ -9,7 +9,7 @@
=t('.outside')
%br
%br
= link_to "RSS", "#{current_user.public_url}.atom"
= link_to t('.atom_feed'), "#{current_user.public_url}.atom"
%br
- if current_user.services
- for service in current_user.services

View file

@ -18,11 +18,11 @@
= link_to( image_tag('deletelabel.png'), "#", :id => "hide_publisher", :title => t('.discard_post'))
%ul#photodropzone
- if current_user.getting_started?
= status.text_area :fake_text, :rows => 2, :value => h(publisher_formatted_text), :tabindex => 1, :placeholder => t('.whats_on_your_mind'),
= status.text_area :fake_text, :rows => 2, :value => h(publisher_formatted_text), :tabindex => 1, :placeholder => "#{t('contacts.index.start_a_conversation')}...",
:title => popover_with_close_html( '1. ' + t('shared.public_explain.share') ),
'data-content' => t('shared.public_explain.new_user_welcome_message')
- else
= status.text_area :fake_text, :rows => 2, :value => h(publisher_formatted_text), :tabindex => 1, :placeholder => t('.whats_on_your_mind')
= status.text_area :fake_text, :rows => 2, :value => h(publisher_formatted_text), :tabindex => 1, :placeholder => "#{t('contacts.index.start_a_conversation')}..."
= status.hidden_field :text, :value => h(publisher_hidden_text), :class => 'clear_on_submit'
#file-upload{:title => t('.upload_photos')}

View file

@ -9,7 +9,7 @@
}
- content_for :header_action do
= submit_tag t('.share'), :class => 'action', :id => "submit_new_message"
= submit_tag t('.share'), :class => 'btn primary', :id => "submit_new_message"
= form_for StatusMessage.new, {:data => {:ajax => false}} do |status|
#message_container

View file

@ -200,6 +200,12 @@ defaults: &defaults
cloudfiles_api_key: 'abc123'
cloudfiles_db_container: 'Database Backup'
cloudfiles_images_container: 'Image Backup'
# Donations
# Leave this blank to not show the request for donations
# Use paypal for recurring donations
paypal_hosted_button_id: ""
#
# Use this section to override default settings in specific environments

View file

@ -110,5 +110,7 @@ stylesheets:
- public/stylesheets/rtl.css
mobile:
- public/stylesheets/bootstrap2.css
- public/stylesheets/bootstrap-responsive.css
- public/stylesheets/mobile.css

View file

@ -11,21 +11,12 @@ if !AppConfig.single_process_mode?
end
end
# Single process-mode hooks using Resque.inline
if AppConfig.single_process_mode?
if Rails.env == 'production'
puts "WARNING: You are running Diaspora in production without Resque workers turned on. Please don't do this."
end
module Resque
def enqueue(klass, *args)
begin
klass.send(:perform, *args)
rescue Exception => e
Rails.logger.warn(e.message)
raise e
nil
end
end
end
Resque.inline = true
end
if AppConfig[:airbrake_api_key].present?

View file

@ -252,7 +252,10 @@ en:
title: "Contacts"
your_contacts: "Your Contacts"
no_contacts: "Looks like you need to add some contacts!"
check_out: "Check out"
no_contacts_message: "Check out %{community_spotlight}"
no_contacts_message_with_aspect: "Check out %{community_spotlight} or %{add_to_aspect_link}"
add_to_aspect_link: "add contacts to %{name}"
community_spotlight: "Community Spotlight"
my_contacts: "My Contacts"
all_contacts: "All Contacts"
only_sharing_with_me: "Only sharing with me"
@ -800,6 +803,7 @@ en:
outside: "Public messages will be available for others outside of Diaspora to see."
logged_in: "logged in to %{service}"
manage: "manage connected services"
atom_feed: "Atom feed"
notification:
new: "New %{type} from %{from}"
contact_list:

View file

@ -10,7 +10,17 @@ app.views.StreamObject = app.views.Base.extend({
widow: 12,
expandPrefix: "",
expandText: Diaspora.I18n.t("show_more"),
userCollapse: false
userCollapse: false,
beforeExpand: function() {
var readMoreDiv = $(this).find('.read-more');
var lastParagraphBeforeReadMore = readMoreDiv.prev();
var firstParagraphAfterReadMore = $(readMoreDiv.next().find('p')[0]);
lastParagraphBeforeReadMore.append(firstParagraphAfterReadMore.text());
firstParagraphAfterReadMore.remove();
readMoreDiv.remove();
}
});
},

View file

@ -0,0 +1,345 @@
.hidden {
display: none;
visibility: hidden;
}
@media (max-width: 480px) {
.page-header h1 small {
display: block;
line-height: 18px;
}
input[class*="span"],
select[class*="span"],
textarea[class*="span"],
.uneditable-input {
display: block;
width: 100%;
height: 28px;
/* Make inputs at least the height of their button counterpart */
/* Makes inputs behave like true block-level elements */
-webkit-box-sizing: border-box;
/* Older Webkit */
-moz-box-sizing: border-box;
/* Older FF */
-ms-box-sizing: border-box;
/* IE8 */
box-sizing: border-box;
/* CSS3 spec*/
}
.input-prepend input[class*="span"], .input-append input[class*="span"] {
width: auto;
}
input[type="checkbox"], input[type="radio"] {
border: 1px solid #ccc;
}
.form-horizontal .control-group > label {
float: none;
width: auto;
padding-top: 0;
text-align: left;
}
.form-horizontal .controls {
margin-left: 0;
}
.form-horizontal .control-list {
padding-top: 0;
}
.form-horizontal .form-actions {
padding-left: 10px;
padding-right: 10px;
}
.modal {
position: absolute;
top: 10px;
left: 10px;
right: 10px;
width: auto;
margin: 0;
}
.modal.fade.in {
top: auto;
}
.modal-header .close {
padding: 10px;
margin: -10px;
}
.carousel-caption {
position: static;
}
}
@media (max-width: 768px) {
.container {
width: auto;
padding: 0 20px;
}
.row {
margin-left: 0;
}
.row > [class*="span"] {
float: none;
display: block;
width: auto;
margin: 0;
}
}
@media (min-width: 768px) and (max-width: 940px) {
.container {
width: 724px;
padding-left: 20px;
padding-right: 20px;
}
.span1 {
width: 42px;
}
.span2 {
width: 104px;
}
.span3 {
width: 166px;
}
.span4 {
width: 228px;
}
.span5 {
width: 290px;
}
.span6 {
width: 352px;
}
.span7 {
width: 414px;
}
.span8 {
width: 476px;
}
.span9 {
width: 538px;
}
.span10 {
width: 600px;
}
.span11 {
width: 662px;
}
.span12 {
width: 724px;
}
.offset1 {
margin-left: 82px;
}
.offset2 {
margin-left: 144px;
}
.offset3 {
margin-left: 206px;
}
.offset4 {
margin-left: 268px;
}
.offset5 {
margin-left: 330px;
}
.offset6 {
margin-left: 392px;
}
.offset7 {
margin-left: 454px;
}
.offset8 {
margin-left: 516px;
}
.offset9 {
margin-left: 578px;
}
.offset10 {
margin-left: 640px;
}
.offset11 {
margin-left: 702px;
}
}
@media (max-width: 940px) {
body {
padding-top: 0;
}
.navbar-fixed-top {
position: static;
margin-bottom: 36px;
}
.navbar-inner {
padding: 5px;
background-image: none;
}
.navbar .container {
padding: 0;
}
.navbar .brand {
padding-left: 10px;
padding-right: 10px;
margin: 0 0 0 -5px;
}
.navbar .nav-collapse {
clear: left;
}
.navbar .nav {
float: none;
margin: 0 0 9px;
}
.navbar .nav > li {
float: none;
}
.navbar .nav > li > a {
margin-bottom: 2px;
}
.navbar .nav > .vertical-divider {
display: none;
}
.navbar .nav > li > a, .navbar .dropdown-menu a {
padding: 6px 15px;
font-weight: bold;
color: #999999;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
.navbar .dropdown-menu li + li a {
margin-bottom: 2px;
}
.navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover {
background-color: #222222;
}
.navbar .dropdown-menu {
position: static;
top: auto;
left: auto;
float: none;
display: block;
max-width: none;
margin: 0 15px;
padding: 0;
background-color: transparent;
border: none;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
.navbar .dropdown-menu:before, .navbar .dropdown-menu:after {
display: none;
}
.navbar .dropdown-menu .divider {
display: none;
}
.navbar-form, .navbar-search {
float: none;
padding: 9px 15px;
margin: 9px 0;
border-top: 1px solid #222222;
border-bottom: 1px solid #222222;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
-moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
}
.navbar .nav.pull-right {
float: none;
margin-left: 0;
}
.navbar-static .navbar-inner {
padding-left: 10px;
padding-right: 10px;
}
.btn-navbar {
display: block;
}
.nav-collapse {
overflow: hidden;
height: 0;
}
}
@media (min-width: 1210px) {
.container {
width: 1170px;
}
.row {
margin-left: -30px;
}
[class*="span"] {
margin-left: 30px;
}
.span1 {
width: 70px;
}
.span2 {
width: 170px;
}
.span3 {
width: 270px;
}
.span4 {
width: 370px;
}
.span5 {
width: 470px;
}
.span6 {
width: 570px;
}
.span7 {
width: 670px;
}
.span8 {
width: 770px;
}
.span9 {
width: 870px;
}
.span10 {
width: 970px;
}
.span11 {
width: 1070px;
}
.span12 {
width: 1170px;
}
.offset1 {
margin-left: 130px;
}
.offset2 {
margin-left: 230px;
}
.offset3 {
margin-left: 330px;
}
.offset4 {
margin-left: 430px;
}
.offset5 {
margin-left: 530px;
}
.offset6 {
margin-left: 630px;
}
.offset7 {
margin-left: 730px;
}
.offset8 {
margin-left: 830px;
}
.offset9 {
margin-left: 930px;
}
.offset10 {
margin-left: 1030px;
}
.offset11 {
margin-left: 1130px;
}
}

3309
public/stylesheets/bootstrap2.css vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,219 +1,3 @@
/*
* HTML5 Boilerplate
*
* What follows is the result of much research on cross-browser styling.
* Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal,
* Kroc Camen, and the H5BP dev community and team.
*
* Detailed information about this CSS: h5bp.com/css
*
* ==|== normalize ==========================================================
*/
/* =============================================================================
HTML5 display definitions
========================================================================== */
article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { display: block; }
audio, canvas, video { display: inline-block; *display: inline; *zoom: 1; }
audio:not([controls]) { display: none; }
[hidden] { display: none; }
/* =============================================================================
Base
========================================================================== */
/*
* 1. Correct text resizing oddly in IE6/7 when body font-size is set using em units
* 2. Force vertical scrollbar in non-IE
* 3. Prevent iOS text size adjust on device orientation change, without disabling user zoom: h5bp.com/g
*/
html { font-size: 100%; overflow-y: scroll; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }
body { margin: 0; font-size: 13px; line-height: 1.231; }
body, button, input, select, textarea { font-family: sans-serif; color: #222; }
/*
* Remove text-shadow in selection highlight: h5bp.com/i
* These selection declarations have to be separate
* Also: hot pink! (or customize the background color to match your design)
*/
::-moz-selection { background: #fe57a1; color: #fff; text-shadow: none; }
::selection { background: #fe57a1; color: #fff; text-shadow: none; }
/* =============================================================================
Links
========================================================================== */
a { color: #00e; }
a:visited { color: #551a8b; }
a:hover { color: #06e; }
a:focus { outline: thin dotted; }
/* Improve readability when focused and hovered in all browsers: h5bp.com/h */
a:hover, a:active { outline: 0; }
/* =============================================================================
Typography
========================================================================== */
abbr[title] { border-bottom: 1px dotted; }
b, strong { font-weight: bold; }
blockquote { margin: 1em 40px; }
dfn { font-style: italic; }
hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; }
ins { background: #ff9; color: #000; text-decoration: none; }
mark { background: #ff0; color: #000; font-style: italic; font-weight: bold; }
/* Redeclare monospace font family: h5bp.com/j */
pre, code, kbd, samp { font-family: monospace, serif; _font-family: 'courier new', monospace; font-size: 1em; }
/* Improve readability of pre-formatted text in all browsers */
pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; }
q { quotes: none; }
q:before, q:after { content: ""; content: none; }
small { font-size: 85%; }
/* Position subscript and superscript content without affecting line-height: h5bp.com/k */
sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
sup { top: -0.5em; }
sub { bottom: -0.25em; }
/* =============================================================================
Lists
========================================================================== */
ul, ol { margin: 1em 0; padding: 0 0 0 40px; }
dd { margin: 0 0 0 40px; }
nav ul, nav ol { list-style: none; list-style-image: none; margin: 0; padding: 0; }
/* =============================================================================
Embedded content
========================================================================== */
/*
* 1. Improve image quality when scaled in IE7: h5bp.com/d
* 2. Remove the gap between images and borders on image containers: h5bp.com/e
*/
img { border: 0; -ms-interpolation-mode: bicubic; vertical-align: middle; }
/*
* Correct overflow not hidden in IE9
*/
svg:not(:root) { overflow: hidden; }
/* =============================================================================
Figures
========================================================================== */
figure { margin: 0; }
/* =============================================================================
Forms
========================================================================== */
form { margin: 0; }
fieldset { border: 0; margin: 0; padding: 0; }
/* Indicate that 'label' will shift focus to the associated form element */
label { cursor: pointer; }
/*
* 1. Correct color not inheriting in IE6/7/8/9
* 2. Correct alignment displayed oddly in IE6/7
*/
legend { border: 0; *margin-left: -7px; padding: 0; }
/*
* 1. Correct font-size not inheriting in all browsers
* 2. Remove margins in FF3/4 S5 Chrome
* 3. Define consistent vertical alignment display in all browsers
*/
button, input, select, textarea { font-size: 100%; margin: 0; vertical-align: baseline; *vertical-align: middle; }
/*
* 1. Define line-height as normal to match FF3/4 (set using !important in the UA stylesheet)
* 2. Correct inner spacing displayed oddly in IE6/7
*/
button, input { line-height: normal; *overflow: visible; }
/*
* Reintroduce inner spacing in 'table' to avoid overlap and whitespace issues in IE6/7
*/
table button, table input { *overflow: auto; }
/*
* 1. Display hand cursor for clickable form elements
* 2. Allow styling of clickable form elements in iOS
*/
button, input[type="button"], input[type="reset"], input[type="submit"], [role="button"] { cursor: pointer; -webkit-appearance: button; }
/*
* Consistent box sizing and appearance
*/
input[type="checkbox"], input[type="radio"] { box-sizing: border-box; padding: 0; }
input[type="search"] { -webkit-appearance: textfield; -moz-box-sizing: content-box; -webkit-box-sizing: content-box; box-sizing: content-box; }
input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; }
/*
* Remove inner padding and border in FF3/4: h5bp.com/l
*/
button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; }
/*
* 1. Remove default vertical scrollbar in IE6/7/8/9
* 2. Allow only vertical resizing
*/
textarea { overflow: auto; vertical-align: top; resize: vertical; }
/* Colors for form validity */
input:valid, textarea:valid { }
input:invalid, textarea:invalid { background-color: #f0dddd; }
/* =============================================================================
Tables
========================================================================== */
table { border-collapse: collapse; border-spacing: 0; }
td { vertical-align: top; }
/* ==|== primary styles =====================================================
Copyright (c) 2010-2011, Diaspora Inc. This file is
licensed under the Affero General Public License version 3 or later. See
the COPYRIGHT file.
========================================================================== */
@import "mixins";
$blue: #3f8fba;
@ -229,10 +13,9 @@ body {
image: url('/images/hatched-bg.jpg');
position: fixed;
/* scale background image down for iOS retina display */
size: 50%;
size: 200px;
}
max-width: 100%;
margin-top: 55px;
padding-top: 55px;
}
.message {
@ -240,15 +23,6 @@ body {
left: 2px; };
}
#main {
text-align: center;
}
.stream {
text-align: left;
max-width: 700px;
}
.stream_element,
.comments {
overflow: auto;
@ -265,15 +39,15 @@ body {
width: 35px;
margin: {
right: 10px; }; }
.from {
a {
margin: {
left: -2px; };
color: #aaaaaa !important;
font: {
weight: bold !important; }; }
color: #444 !important;
font-weight: bold;
}
margin-bottom: 2px;
height: 45px; }
height: 45px;
}
> .content,
.reshare > .content {
@ -289,13 +63,6 @@ body {
.time {
font: {
weight: normal; }; }
p {
margin: 0 auto;
font-size: 14px;
line-height: 19px; }
margin: 10px {
top: 10px;
bottom: 0; };
padding: 0 !important;
}
.shield{
@ -317,10 +84,10 @@ body {
}
.stream_element .comments {
width: 100%;
padding: 0;
margin: 0;
top: 8px;
width: 100%;
top: 3px;
.content {
padding: 0;
}
@ -340,38 +107,13 @@ body {
#login_form {
padding: 0;
padding-bottom: 10px;
margin: auto 20px;
/* ensure url bar is banished from view on iOS */
margin-bottom: 40px !important;
.login-container {
padding: 10px;
}
.row {
margin-bottom: 10px;
.login-submit {
float: right;
}
}
.centered{
text-align: center;
}
label {
color: #ccc;
font-size: larger;
font-weight: bold;
}
input[type='text'],
input[type='password'] {
font-size: 18px;
font-weight: bold;
max-width:90%;
}
}
.stream_element, #login_form {
@ -379,6 +121,7 @@ body {
@include box-shadow(0, 1px, 2px, rgba(0, 0, 0, 0.2));
background-color: #fff;
margin-bottom: 10px;
border: 1px solid #bbb;
border-top: 1px solid #ddd;
@ -398,12 +141,9 @@ body {
#main_stream {
font: {
size: 0.95em; }; }
.from {
font: {
size: larger; }; }
margin-left: -10px;
margin-right: -10px;
}
.more-link {
-webkit-box-shadow: inset 0 1px 5px #777, 0 1px 1px rgba(0,0,0,0.4);
@ -490,34 +230,24 @@ body {
padding: 0;
}
#author_info.profile {
box-shadow: inset 0 -1px 3px #111;
margin-top: -10px;
text-align: left;
#author_info {
height: 100px;
position: relative;
h2 {
color: #ccc;
}
background: {
color: #333; };
border: {
bottom: 1px solid black; };
height: 90px;
padding: 10px;
margin: {
bottom: 6px; };
img {
float: left;
height: 90px;
width: 90px;
margin: {
right: 10px;
}
position: absolute;
}
.content {
padding: {
left: 100px; }; }
left: 100px;
};
}
.description {
font: {
weight: normal;
@ -527,7 +257,11 @@ body {
.right {
float: right; }
header {
.navbar {
@include box-shadow(0,1px,2px,#333);
}
.navbar-inner {
@include box-shadow(0,1px,2px,#333);
background: {
@ -535,25 +269,16 @@ header {
}
width: 100%;
position: fixed;
z-index: 10;
top: 0;
/* force hardware acceleration on webkit browsers
10/17/2011 - removed for now, causes ghost doubles of links on some Android browsers */
/*-webkit-transform: translateZ(0);*/
border: {
bottom: 1px solid #222;
}
padding: 2px 5px;
.right {
float: right; } }
}
.stream_element {
/* force hardware acceleration on webkit browsers
10/17/2011 - removed for now, causes ghost doubles of links on some Android browsers */
/*-webkit-transform: translateZ(0);*/
#header_title {
position: relative;
top: -3px;
}
footer {
@ -571,21 +296,21 @@ footer {
.bottom_bar {
@include border-radius(0, 0, 5px, 5px);
box-shadow: inset 0 2px 5px -3px #999;
z-index: 3;
display: block;
position: relative;
padding: 10px;
padding-top: 8px;
background: #eee;
margin: {
top: 10px; };
border: {
top: 1px solid #ccc;
top: 1px solid #ddd;
};
min-height: 24px;
min-height: 22px;
> a,
.show_comments {
@ -597,9 +322,6 @@ footer {
.show_comments {
position: relative;
top: 3px;
font: {
size: larger;
}
color: #ccc;
}
@ -660,11 +382,8 @@ footer {
float: right; }
.stream_element .photo_attachments {
@include border-radius(3px);
@include border-radius(3px, 3px, 0, 0);
background: {
color: #999;
}
border: {
bottom: 1px solid #ccc;
}
@ -675,7 +394,8 @@ footer {
}
a {
padding: 0; }
margin-top: 0; }
margin-top: 0;
}
.photo_area {
@include border-radius(3px);
@ -684,12 +404,15 @@ footer {
.image_link {
display: inline-block;
background: {
size: 24px;
size: 20px;
repeat: no-repeat;
position: center; };
height: 16px;
width: 24px;
height: 13px;
width: 20px;
padding: 5px;
margin: {
left: 5px; };
@ -719,12 +442,6 @@ footer {
}
}
.compose_icon {
position: absolute;
top: 8px;
right: 15px;
}
#new_status_message {
text-align: left;
position: absolute;
@ -764,35 +481,6 @@ footer {
}
}
textarea {
font-size: larger !important;
}
form {
input:not([type='checkbox']),
textarea {
-webkit-appearance: none;
text-size: larger;
}
}
.btn,
input[type=submit] {
@include border-radius(3px);
background-color: #ddd;
color: #666;
font-weight: bold;
padding: 10px;
border: 1px solid #ccc;
min-width: 100px;
&.action {
color: #fff;
background-color: green;
border: 1px solid #888;
}
}
select {
font-size: larger;
padding: 7px;
@ -801,15 +489,6 @@ select {
.new_comment {
padding: 10px 0;
padding-top: 20px;
textarea {
width: 98%;
}
.actions {
text-align: right;
margin-top: 10px;
}
}
.comment.add_comment_bottom_link_container {
@ -820,10 +499,10 @@ select {
.post_stats {
position: absolute;
font-size: larger;
right: 10px;
top: 36px;
right: 8px;
top: 31px;
z-index: 2;
span {
color: #666;
font-weight: bold;
@ -849,17 +528,6 @@ select {
line-height: 16px;
}
header {
input {
position: absolute;
top: 8px;
right: 15px;
padding: 5px !important;
min-width: 75px !important;
border: 1px solid #444 !important;
}
}
.new_status_message {
min-height: 300px;
}
@ -887,90 +555,23 @@ header {
}
}
/*
* Media queries for responsive design https://github.com/shichuan/mobile-html5-boilerplate/wiki/The-Style
*/
/* Styles for desktop and large screen ----------- */
/*styles for 800px and up!*/
@media only screen and (min-width: 800px) {
/* Styles */
}/*/mediaquery*/
/* iPhone 4, Opera Mobile 11 and other high pixel ratio devices ----------- */
@media
only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min--moz-device-pixel-ratio: 1.5),
only screen and (min-device-pixel-ratio: 1.5) {
/* Styles */
.compose_icon {
height: 28px;
width: 28px;
margin-top: 3px;
}
.navbar-inner .right {
position: absolute;
right: 12px;
top: 0px;
}
.navbar-fixed-top {
position: fixed !important;
/* ==|== non-semantic helper classes ========================================
Please define your styles before this section.
========================================================================== */
/* prevent callout */
.nocallout {-webkit-touch-callout: none;}
/* Text overflow with ellipsis */
.ellipsis {
text-overflow: ellipsis;
max-height: 45px !important;
min-height: 45px !important;
height: 45px !important;
overflow: hidden;
white-space: nowrap;
}
/* A hack for HTML5 contenteditable attribute on mobile */
textarea[contenteditable] {-webkit-appearance: none;}
/* A workaround for S60 3.x and 5.0 devices which do not animated gif images if they have been set as display: none */
.gifhidden {position: absolute; left: -100%;}
/* For image replacement */
.ir { display: block; border: 0; text-indent: -999em; overflow: hidden; background-color: transparent; background-repeat: no-repeat; text-align: left; direction: ltr; }
.ir br { display: none; }
/* Hide from both screenreaders and browsers: h5bp.com/u */
.hidden { display: none !important; visibility: hidden; }
/* Hide only visually, but have it available for screenreaders: h5bp.com/v */
.visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
/* Extends the .visuallyhidden class to allow the element to be focusable when navigated to via the keyboard: h5bp.com/p */
.visuallyhidden.focusable:active, .visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; }
/* Hide visually and from screenreaders, but maintain layout */
.invisible { visibility: hidden; }
/* Contain floats: h5bp.com/q */
.clearfix:before, .clearfix:after { content: ""; display: table; }
.clearfix:after { clear: both; }
.clearfix { *zoom: 1; }
/* ==|== print styles =======================================================
Print styles.
Inlined to avoid required HTTP connection: h5bp.com/r
========================================================================== */
@media print {
* { background: transparent !important; color: black !important; text-shadow: none !important; filter:none !important; -ms-filter: none !important; } /* Black prints faster: h5bp.com/s */
a, a:visited { text-decoration: underline; }
a[href]:after { content: " (" attr(href) ")"; }
abbr[title]:after { content: " (" attr(title) ")"; }
.ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } /* Don't show links for images, or javascript/internal links */
pre, blockquote { border: 1px solid #999; page-break-inside: avoid; }
thead { display: table-header-group; } /* h5bp.com/t */
tr, img { page-break-inside: avoid; }
img { max-width: 100% !important; }
@page { margin: 0.5cm; }
p, h2, h3 { orphans: 3; widows: 3; }
h2, h3 { page-break-after: avoid; }
}
}

View file

@ -14,14 +14,21 @@ describe StreamsController do
posts = []
time = Time.now
10.times do
10.times do |i|
Timecop.travel time += 1.day do
Timecop.travel time += 1.minute
posts << alice.post(:status_message, :text => "hella infos yo!", :to => alice.aspects.first.id)
Timecop.travel time += 1.minute
posts << alice.post(:reshare, :root_guid => Factory(:status_message, :public => true).guid, :to => 'all')
Timecop.travel time += 1.minute
posts << alice.post(:status_message, :text => "you're gonna love this.'", :to => alice.aspects.first.id)
if i == 9
posts << alice.post(:status_message,
:text => "LONG POST TO TEST SHOW MORE. Cardigan trust fund vice, sartorial twee pitchfork +1 quinoa whatever readymade gluten-free. Seitan brooklyn mustache quinoa carles. Gentrify ethical four loko you probably haven't heard of them 3 wolf moon helvetica. Terry richardson +1 artisan, raw denim iphone four loko leggings organic helvetica retro mcsweeney's put a bird on it skateboard 3 wolf moon. Fap skateboard high life 8-bit. Iphone ethical tumblr lo-fi, dreamcatcher irony whatever farm-to-table mustache tofu marfa. Before they sold out next level lomo farm-to-table leggings, williamsburg jean shorts messenger bag. Synth readymade Austin artisan art party, cardigan vice mustache 3 wolf moon craft beer. Messenger bag before they sold out tattooed wayfarers viral photo booth. Food truck master cleanse locavore raw denim. Sustainable master cleanse seitan, trust fund cred yr keffiyeh butcher mlkshk put a bird on it gentrify you probably haven't heard of them vinyl craft beer gluten-free. Master cleanse retro next level messenger bag craft beer. DIY leggings dreamcatcher lo-fi. Etsy carles tattooed mcsweeney's food truck DIY wolf shoreditch.",
:to => alice.aspects.first.id)
else
posts << alice.post(:status_message, :text => "you're gonna love this.", :to => alice.aspects.first.id)
end
Timecop.travel time += 1.minute
alice.like(1, :target => posts.last)
end

View file

@ -85,11 +85,6 @@ describe PeopleController do
assigns[:people].map { |x| x.id }.should =~ [@eugene.id, eugene2.id]
end
it "assigns a normalized tag" do
get :index, :q => "foo"
assigns[:normalized_tag_for_query].should == "foo"
end
it "succeeds if there is exactly one match" do
get :index, :q => "Korth"
assigns[:people].length.should == 1
@ -104,13 +99,11 @@ describe PeopleController do
it 'succeeds if you search for the empty term' do
get :index, :q => ''
assigns[:normalized_tag_for_query].should be_empty
response.should be_success
end
it 'succeeds if you search for punctuation' do
get :index, :q => '+'
assigns[:normalized_tag_for_query].should be_empty
response.should be_success
end

View file

@ -49,6 +49,11 @@ describe PostsController do
get :show, :id => photo.id
response.should be_success
end
it 'redirects if the post is missing' do
get :show, :id => 1234567
response.should be_redirect
end
end
context 'user not signed in' do

View file

@ -0,0 +1,18 @@
require 'spec_helper'
describe TagsHelper do
describe '#looking_for_tag_link' do
it 'returns nil if there is a @ in the query' do
helper.stub(:search_query).and_return('foo@bar.com')
helper.looking_for_tag_link.should be_nil
end
it 'returns nil if it normalizes to blank' do
helper.stub(:search_query).and_return('++')
helper.looking_for_tag_link.should be_nil
end
it 'returns a link to the tag otherwise' do
helper.stub(:search_query).and_return('foo')
helper.looking_for_tag_link.should include(helper.tag_link)
end
end
end

View file

@ -4,25 +4,25 @@ describe("app.views.Stream", function(){
this.posts = $.parseJSON(spec.readFixture("multi_stream_json"))["posts"];
this.stream = new app.models.Stream()
this.stream = new app.models.Stream();
this.stream.add(this.posts);
this.view = new app.views.Stream({model : this.stream});
app.stream.bind("fetched", this.collectionFetched, this) //untested
app.stream.bind("fetched", this.collectionFetched, this); //untested
// do this manually because we've moved loadMore into render??
this.view.render();
_.each(this.view.collection.models, function(post){ this.view.addPost(post); }, this);
})
});
describe("initialize", function(){
it("binds an infinite scroll listener", function(){
spyOn($.fn, "scroll");
new app.views.Stream({model : this.stream});
expect($.fn.scroll).toHaveBeenCalled()
})
})
expect($.fn.scroll).toHaveBeenCalled();
});
});
describe("#render", function(){
beforeEach(function(){
@ -30,42 +30,78 @@ describe("app.views.Stream", function(){
this.reshare = this.stream.posts.models[1];
this.statusElement = $(this.view.$("#" + this.statusMessage.get("guid")));
this.reshareElement = $(this.view.$("#" + this.reshare.get("guid")));
})
});
context("when rendering a Status Mesasage", function(){
it("shows the status message in the content area", function(){
expect(this.statusElement.find(".post-content p").text()).toContain("you're gonna love this") //markdown'ed
})
})
})
context("when rendering a status message", function(){
it("shows the message in the content area", function(){
expect(this.statusElement.find(".post-content p").text()).toContain("LONG POST"); //markdown'ed
});
});
});
describe('clicking read more', function() {
var readMoreLink;
beforeEach(function() {
this.statusMessage = this.stream.posts.models[0];
this.statusElement = $(this.view.$("#" + this.statusMessage.get("guid")));
readMoreLink = this.statusElement.find('.read-more a');
readMoreLink.text("read more");
});
it('expands the post', function() {
expect(this.statusElement.find('.collapsible .details').attr('style')).toContain('display: none;');
readMoreLink.click();
expect(this.statusElement.find('.collapsible .details').attr('style')).not.toContain('display: none;');
});
it('removes the read-more div', function() {
expect(this.statusElement.find('.read-more').length).toEqual(1);
readMoreLink.click();
expect(this.statusElement.find('.read-more').length).toEqual(0);
});
it('collapses the p elements on webkit', function() {
// The expander plugin has different behavior on firefox and webkit >.<
expect(this.statusElement.find('.collapsible p').length).toEqual(2);
readMoreLink.click();
if(this.statusElement.find('.collapsible .summary').length > 0) {
// Firefox
expect(this.statusElement.find('.collapsible p').length).toEqual(2);
} else {
// Chrome
expect(this.statusElement.find('.collapsible p').length).toEqual(1);
}
});
});
describe("infScroll", function(){
// NOTE: inf scroll happens at 500px
it("calls render when the user is at the bottom of the page", function(){
spyOn($.fn, "height").andReturn(0)
spyOn($.fn, "scrollTop").andReturn(100)
spyOn(this.view, "render")
spyOn($.fn, "height").andReturn(0);
spyOn($.fn, "scrollTop").andReturn(100);
spyOn(this.view, "render");
this.view.infScroll();
expect(this.view.render).toHaveBeenCalled();
})
})
});
});
describe("removeLoader", function() {
it("emptys the pagination div when the stream is fetched", function(){
$("#jasmine_content").append($('<div id="paginate">OMG</div>'))
expect($("#paginate").text()).toBe("OMG")
this.view.stream.trigger("fetched")
expect($("#paginate")).toBeEmpty()
})
})
$("#jasmine_content").append($('<div id="paginate">OMG</div>'));
expect($("#paginate").text()).toBe("OMG");
this.view.stream.trigger("fetched");
expect($("#paginate")).toBeEmpty();
});
});
describe("unbindInfScroll", function(){
it("unbinds scroll", function() {
spyOn($.fn, "unbind")
this.view.unbindInfScroll()
expect($.fn.unbind).toHaveBeenCalledWith("scroll")
})
})
})
spyOn($.fn, "unbind");
this.view.unbindInfScroll();
expect($.fn.unbind).toHaveBeenCalledWith("scroll");
});
});
});