Merge branch 'master' of github.com:Retrospring/retrospring into optimize-js

This commit is contained in:
Yuki 2015-05-18 14:36:46 +05:30
commit 7a5b1cf1de
57 changed files with 940 additions and 110 deletions

View File

@ -1,6 +1,12 @@
language: ruby language: ruby
cache: bundler
rvm: 2.1 rvm: 2.1
services:
- redis-server
before_script: before_script:
- cp config/database.yml.postgres config/database.yml - cp config/database.yml.postgres config/database.yml
- cp config/justask.yml.example config/justask.yml - cp config/justask.yml.example config/justask.yml
- bundle exec rake db:drop db:create db:migrate db:test:prepare - bundle exec rake db:drop db:create db:migrate db:test:prepare
notifications:
slack:
secure: aXIzsmSiwfwwIjBq759esN2+0jVXHt4XYRmhT6cpvkbtdE4LQapnco7XA3c6hD5LXvR67KZgBQjPcayhaPfbRCWbmmU5IXZyXpH1u+CcGsOZyDsStnGWF+AjYTMhWz3d0t+vbYDk3P4+hqXGvV3gi04a4nqNFI+soohBT919slJt9hqCY/fZYRkpXrn+F+OHSLRwp9R+SSznpwPAxyL0AXcqrRaThHupFtWQCCMTDGDPBfz5oJWzF7cWK+BRar2WIZ3q5lnp7CqTRbOlcpIDnGUMVTFLH7H13h/NZclaqqmgLZ0iCbs6sqN6ZLTVY6HQoUG8qJItEOomFQ6eXMgZ9ZZmINaDINojLjg1b2Y8mrwE6IXtDP9pQ/Hqth0kn1cCW1mQyjvhus+uEJ2N1y4QcZVoHFUCaOj/oEnCb+F8ZGKICtODRNWPEnX1cfLAxK9Hhc6zfkP5GAK9DNxaZNo0Zxvc2eVyS6XnnNzvLFjI7RVju+bJdQarW2nficbawiU8Z0KplKuQCA5yyC2CmKh4wWbBLcNd5y4iqcKIn0pdbc+xCPB89JgOyOfIPemtNpBhev2tffbUCH6hQ2j6C1iDCEZezLW/7oW+SAPGYSySw0uLGeqmB1oLRlDudgJGIITgP+hOhMcOKcQRM7+QwVAgxR2nMGOWAX5HD5aJeCZ+Z3Q=

View File

@ -64,6 +64,9 @@ gem 'redis'
group :development do group :development do
gem 'spring' gem 'spring'
# ten thousand raises no more!
gem 'byebug'
gem 'web-console'
end end
group :production do group :production do

View File

@ -51,6 +51,8 @@ GEM
coderay (>= 1.0.0) coderay (>= 1.0.0)
erubis (>= 2.6.6) erubis (>= 2.6.6)
rack (>= 0.9.0) rack (>= 0.9.0)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
bootstrap-sass (3.2.0.2) bootstrap-sass (3.2.0.2)
sass (~> 3.2) sass (~> 3.2)
bootstrap3-datetimepicker-rails (4.7.14) bootstrap3-datetimepicker-rails (4.7.14)
@ -60,6 +62,8 @@ GEM
railties (>= 3.1) railties (>= 3.1)
buftok (0.2.0) buftok (0.2.0)
builder (3.2.2) builder (3.2.2)
byebug (4.0.5)
columnize (= 0.9.0)
capybara (2.4.4) capybara (2.4.4)
mime-types (>= 1.16) mime-types (>= 1.16)
nokogiri (>= 1.3.3) nokogiri (>= 1.3.3)
@ -81,10 +85,12 @@ GEM
coffee-script-source coffee-script-source
execjs execjs
coffee-script-source (1.9.1.1) coffee-script-source (1.9.1.1)
columnize (0.9.0)
connection_pool (2.2.0) connection_pool (2.2.0)
crass (1.0.2) crass (1.0.2)
daemons (1.2.2) daemons (1.2.2)
database_cleaner (1.4.1) database_cleaner (1.4.1)
debug_inspector (0.0.2)
delayed_paperclip (2.9.1) delayed_paperclip (2.9.1)
paperclip (>= 3.3) paperclip (>= 3.3)
devise (3.4.1) devise (3.4.1)
@ -446,6 +452,11 @@ GEM
raindrops (~> 0.7) raindrops (~> 0.7)
warden (1.2.3) warden (1.2.3)
rack (>= 1.0) rack (>= 1.0)
web-console (2.1.2)
activemodel (>= 4.0)
binding_of_caller (>= 0.7.2)
railties (>= 4.0)
sprockets-rails (>= 2.0, < 4.0)
websocket-driver (0.5.4) websocket-driver (0.5.4)
websocket-extensions (>= 0.1.0) websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2) websocket-extensions (0.1.2)
@ -465,6 +476,7 @@ DEPENDENCIES
bootstrap3-datetimepicker-rails (~> 4.7.14) bootstrap3-datetimepicker-rails (~> 4.7.14)
bootstrap_form bootstrap_form
bootswatch-rails bootswatch-rails
byebug
capybara capybara
coffee-rails (~> 4.1.0) coffee-rails (~> 4.1.0)
database_cleaner database_cleaner
@ -517,5 +529,6 @@ DEPENDENCIES
twitter twitter
uglifier (>= 1.3.0) uglifier (>= 1.3.0)
unicorn unicorn
web-console
will_paginate will_paginate
will_paginate-bootstrap will_paginate-bootstrap

View File

@ -1,4 +1,5 @@
# Retrospring [![Build Status](https://snap-ci.com/Retrospring/retrospring/branch/master/build_image)](https://snap-ci.com/Retrospring/retrospring/branch/master) # Retrospring [![Build Status](https://travis-ci.org/Retrospring/retrospring.svg)](https://travis-ci.org/Retrospring/retrospring) [![Bugs](https://badge.waffle.io/retrospring/bugs.svg?label=in+progress&title=In+Progress)](http://waffle.io/retrospring/bugs)
This is the source code that powers Retrospring. Yep, all of it. Including This is the source code that powers Retrospring. Yep, all of it. Including
all the branches where we left off. all the branches where we left off.

View File

@ -8,6 +8,7 @@
#= require growl #= require growl
#= require cheet #= require cheet
#= require jquery.guillotine #= require jquery.guillotine
#= require jquery.particleground
#= require sweet-alert #= require sweet-alert
# local requires to be seen by everyone: # local requires to be seen by everyone:
#= require_tree ./answerbox #= require_tree ./answerbox
@ -44,5 +45,9 @@ _ready = ->
if typeof sweetAlertInitialize != "undefined" if typeof sweetAlertInitialize != "undefined"
sweetAlertInitialize() sweetAlertInitialize()
particleground document.getElementById('particles'),
dotColor: '#5e35b1'
lineColor: '#5e35b1'
$(document).ready _ready $(document).ready _ready
$(document).on 'page:load', _ready $(document).on 'page:load', _ready

View File

@ -6,6 +6,7 @@ body {
background-color: #fafafa; background-color: #fafafa;
} }
@import "scss/variable";
@import "scss/generic"; @import "scss/generic";
@import "scss/answerbox"; @import "scss/answerbox";
@import "scss/comments"; @import "scss/comments";
@ -15,21 +16,12 @@ body {
@import "scss/user"; @import "scss/user";
@import "scss/notifications"; @import "scss/notifications";
@import "scss/groups"; @import "scss/groups";
@import "scss/mobile";
.j2-page { .j2-page {
padding-top: 30px; padding-top: 30px;
} }
.question-page {
padding-top: 100px;
}
@media(max-width: $screen-xs-max) {
.question-page {
padding-top: 130px;
}
}
.centre { .centre {
text-align: center; text-align: center;
} }
@ -69,7 +61,7 @@ body {
} }
.j2-lh { .j2-lh {
color: #fff; color: $main-color;
} }
.about--moderator { .about--moderator {
padding-left: 0px; padding-left: 0px;
@ -167,3 +159,39 @@ body {
border-bottom-left-radius: 2px; border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px; border-bottom-right-radius: 2px;
} }
.particle-jumbotron {
padding: 0px;
overflow: hidden;
position: relative;
width: 100%;
}
.particle-content {
position: relative;
top: 0;
padding-top: 48px;
padding-bottom: 48px;
padding-left: 30px;
padding-right: 30px;
}
#particles {
position: absolute;
width: 100%;
height: 100%;
}
.icon-showcase {
font-size: 78px;
text-align: center;
display: block;
}
.heading-showcase {
margin-top: 5px;
}
.discover {
padding-top: 20px;
}

View File

@ -6,6 +6,10 @@
list-style-type: none; list-style-type: none;
} }
.comments .pull-right {
margin-top: -13px;
}
.comments--box { .comments--box {
z-index: 99; z-index: 99;
} }
@ -24,6 +28,10 @@
word-break: normal; word-break: normal;
} }
.comments--content p {
margin-bottom: 0px;
}
.comments--media { .comments--media {
overflow: visible !important; overflow: visible !important;
} }

View File

@ -0,0 +1,4 @@
@media (max-width: 768px) {
@import "mobile/settings";
@import "mobile/profile";
}

View File

@ -0,0 +1,76 @@
.container.headerable:not(.profile--no-header) {
margin-top: 0;
padding-top: 0;
}
#profile--header:not(.profile--no-header) {
min-width: 0px;
* {
min-width: 0px;
}
}
.container.headerable {
#profile-info {
box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.1);
margin-bottom: 15px;
#profile.panel, #profile-stats.panel {
box-shadow: none;
margin-bottom: 0;
}
#profile.panel {
font-size: 0;
.profile--avatar {
width: 64px;
position: relative;
top: -15px;
left: 5px;
display: inline;
}
.profile--panel-badge {
display: inline-block;
padding: 0 5px;
vertical-align: top;
width: auto;
margin-top: -15px;
&:nth-child(2) {
margin-left: 5px;
}
.fa {
font-size: 15px;
}
}
.panel-body {
font-size: 15px;
.profile--panel-name {
margin-top: -75px;
margin-left: 60px
}
}
}
#profile-stats {
border: none;
.panel-heading {
display: none;
}
.panel-body {
font-size: 0px;
padding: 0;
.row {
width: 50%;
display: inline-block;
font-size: 12px;
margin: 0;
}
}
}
}
}

View File

@ -0,0 +1,11 @@
#profile-header-media {
clear: both;
display: block;
.pull-left {
float: none !important;
clear: both;
img {
width: 100%
}
}
}

View File

@ -27,6 +27,13 @@
border-color: #fff; border-color: #fff;
} }
.panel-question.question-hidden {
visibility: hidden;
position: relative;
box-shadow: none;
z-index: -1;
}
.answerbox--question-media, .question-media, .question-body { .answerbox--question-media, .question-media, .question-body {
overflow: visible !important; overflow: visible !important;
} }

View File

@ -0,0 +1,29 @@
class DiscoverController < ApplicationController
before_filter :authenticate_user!
def index
top_x = 10 # only display the top X items
@popular_answers = Answer.where("created_at > ?", Time.now.ago(1.week)).order(:smile_count).reverse_order.limit(top_x)
@most_discussed = Answer.where("created_at > ?", Time.now.ago(1.week)).order(:comment_count).reverse_order.limit(top_x)
@popular_questions = Question.where("created_at > ?", Time.now.ago(1.week)).order(:answer_count).reverse_order.limit(top_x)
@new_users = User.where("asked_count > 0").order(:id).reverse_order.limit(top_x)
# .user = the user
# .question_count = how many questions did the user ask
@users_with_most_questions = Question.select('user_id, COUNT(*) AS question_count').
where("created_at > ?", Time.now.ago(1.week)).
where(author_is_anonymous: false).
group(:user_id).
order('question_count').
reverse_order.limit(top_x)
# .user = the user
# .answer_count = how many questions did the user answer
@users_with_most_answers = Answer.select('user_id, COUNT(*) AS answer_count').
where("created_at > ?", Time.now.ago(1.week)).
group(:user_id).
order('answer_count').
reverse_order.limit(top_x)
end
end

View File

@ -93,4 +93,64 @@ module ApplicationHelper
return true if user_agent.match /^Mozilla\/\d+\.\d+ \(i(?:Phone|Pad|Pod); CPU(?:.*) like Mac OS X\)(?:.*) Mobile(?:\S*)$/ return true if user_agent.match /^Mozilla\/\d+\.\d+ \(i(?:Phone|Pad|Pod); CPU(?:.*) like Mac OS X\)(?:.*) Mobile(?:\S*)$/
false false
end end
def generate_title(name, junction = nil, content = nil, s = false)
if s
if name[-1].downcase != "s"
name = name + "'s"
else
name = name + "'"
end
end
list = [name]
list.push junction unless junction.nil?
unless content.nil?
content = strip_markdown(content)
if content.length > 45
content = content[0..42] + "..."
end
list.push content
end
list.push "|", APP_CONFIG['site_name']
list.join " "
end
def question_title(question)
name = user_screen_name question.user, question.author_is_anonymous, false
generate_title name, "asked", question.content
end
def answer_title(answer)
name = user_screen_name answer.user, false, false
generate_title name, "answered", answer.question.content
end
def user_title(user, junction = nil)
name = user_screen_name user, false, false
generate_title name, junction, nil, !junction.nil?
end
def questions_title(user)
user_title user, "questions"
end
def answers_title(user)
user_title user, "answers"
end
def smiles_title(user)
user_title user, "smiles"
end
def comments_title(user)
user_title user, "comments"
end
def group_title(group)
generate_title group.name
end
end end

View File

@ -0,0 +1,2 @@
module DiscoverHelper
end

View File

@ -1,3 +1,3 @@
- provide(:title, "#{@answer.user.display_name.blank? ? "@#{@answer.user.screen_name}'s" : "#{@answer.user.display_name}'s"} answer | #{APP_CONFIG['site_name']}") - provide(:title, answer_title(@answer))
.container.j2-page .container.j2-page
= render 'shared/answerbox', a: @answer = render 'shared/answerbox', a: @answer

View File

@ -1,4 +1,4 @@
- provide(:title, "Resend confirmation instructions | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Resend confirmation instructions"))
.container .container
%h1 Resend confirmation instructions %h1 Resend confirmation instructions
= bootstrap_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| = bootstrap_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f|

View File

@ -1,4 +1,4 @@
- provide(:title, "Change your password | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Reset Password"))
.container .container
%h1 Change your password %h1 Change your password
= bootstrap_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| = bootstrap_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f|

View File

@ -1,4 +1,4 @@
- provide(:title, "Forgot your password? | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Forgot your Password?"))
.container .container
%h1 Forgot your password? %h1 Forgot your password?
= bootstrap_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| = bootstrap_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f|

View File

@ -1,4 +1,4 @@
- provide(:title, "Sign up | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Sign Up"))
.container .container
%h1 Sign up %h1 Sign up

View File

@ -1,4 +1,4 @@
- provide(:title, "Sign in | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Sign In"))
.container .container
%h1 Sign in %h1 Sign in
= render 'layouts/messages' = render 'layouts/messages'

View File

@ -1,4 +1,4 @@
- provide(:title, "Unlock | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Unlock"))
.container .container
%h1 Resend unlock instructions %h1 Resend unlock instructions
= render 'layouts/messages' = render 'layouts/messages'

View File

@ -0,0 +1,3 @@
.tab-pane.active.fade.in{role: "tabpanel", id: "answers"}
- answers.each do |a|
= render 'shared/answerbox', a: a

View File

@ -0,0 +1,3 @@
.tab-pane.fade{role: "tabpanel", id: "asked"}
- asked.each do |user|
= render 'discover/userbox', u: user.user, type: "asked", q: user.question_count

View File

@ -0,0 +1,3 @@
.tab-pane.fade{role: "tabpanel", id: "comments"}
- comments.each do |a|
= render 'shared/answerbox', a: a

View File

@ -0,0 +1,3 @@
.tab-pane.fade{role: "tabpanel", id: "answered"}
- answered.each do |user|
= render 'discover/userbox', u: user.user, type: "most", a: user.answer_count

View File

@ -0,0 +1,3 @@
.tab-pane.active.fade.in{role: "tabpanel", id: "new"}
- new.each do |user|
= render 'discover/userbox', u: user, type: "new"

View File

@ -0,0 +1,3 @@
.tab-pane.fade{role: "tabpanel", id: "questions"}
- questions.each do |q|
= render 'shared/question', q: q, type: "discover"

View File

@ -0,0 +1,26 @@
.panel.panel-default.questionbox{data: { id: u.id }}
.panel-body
.media
.pull-left
%a{href: show_user_profile_path(u.screen_name)}
%img.answerbox--img{src: u.profile_picture.url(:medium)}
.media-body
%h6.media-heading
- if u.display_name.blank?
%a{href: show_user_profile_path(u.screen_name)}
%span= "@#{u.screen_name}"
- else
%a{href: show_user_profile_path(u.screen_name)}
%span= u.display_name
%span.text-muted= "@#{u.screen_name}"
%p.answerbox--question-text
- if type == "new"
registered
= time_ago_in_words(u.created_at)
ago
- elsif type == "most"
answered
= pluralize(a, "question")
- else
asked
= pluralize(q, "question")

View File

@ -0,0 +1,48 @@
- provide(:title, generate_title("Discover"))
.jumbotron.j2-jumbo.text-center.particle-jumbotron
#particles
.particle-content
%h1 Discover
%p
The perfect place to find interesting content from the last week on
= succeed '!' do
= APP_CONFIG['site_name']
.container
.row
.col-md-7.col-sm-6
%h2 Popular Content
%p Answers with most smiles and most answered questions
%div{role: "tabpanel"}
%ul.nav.nav-tabs{role: "tablist"}
%li.active{role: "presentation"}
%a{href: "#answers", role: "tab", aria: {controls: "answers"}, data: {toggle: "tab"}}
Answers
%li{role: "presentation"}
%a{href: "#questions", role: "tab", aria: {controls: "questions"}, data: {toggle: "tab"}}
Questions
%li{role: "presentation"}
%a{href: "#comments", role: "tab", aria: {controls: "comments"}, data: {toggle: "tab"}}
Most Comments
.tab-content.discover
= render 'discover/tab_answers', answers: @popular_answers
= render 'discover/tab_questions', questions: @popular_questions
= render 'discover/tab_discussed', comments: @most_discussed
.col-md-5.col-sm-6
%h2 People
%p Newcomers and people who asked the most questions
%div{role: "tabpanel"}
%ul.nav.nav-tabs{role: "tablist"}
%li.active{role: "presentation"}
%a{href: "#new", role: "tab", aria: {controls: "new"}, data: {toggle: "tab"}}
New Users
%li{role: "presentation"}
%a{href: "#asked", role: "tab", aria: {controls: "asked"}, data: {toggle: "tab"}}
Most Asked Questions
%li{role: "presentation"}
%a{href: "#answered", role: "tab", aria: {controls: "answered"}, data: {toggle: "tab"}}
Most Answers
.tab-content.discover
= render 'discover/tab_new', new: @new_users
= render 'discover/tab_asked', asked: @users_with_most_questions
= render 'discover/tab_most', answered: @users_with_most_answers
= render 'shared/links'

View File

@ -1,4 +1,4 @@
- provide(:title, "#{@group.display_name} | #{APP_CONFIG['site_name']}") - provide(:title, group_title(@group))
= render 'static/mobile_nav' = render 'static/mobile_nav'
.container.j2-page .container.j2-page
.col-md-3.col-sm-3 .col-md-3.col-sm-3

View File

@ -1,4 +1,4 @@
- provide(:title, "Inbox | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Inbox"))
.container.j2-page .container.j2-page
.row .row
.col-md-3.col-xs-12.col-sm-3.hidden-xs .col-md-3.col-xs-12.col-sm-3.hidden-xs

View File

@ -22,6 +22,7 @@
%ul.nav.navbar-nav %ul.nav.navbar-nav
= nav_entry "Timeline", root_path = nav_entry "Timeline", root_path
= nav_entry "Inbox", "/inbox", badge: inbox_count = nav_entry "Inbox", "/inbox", badge: inbox_count
= nav_entry "Discover", discover_path
%ul.nav.navbar-nav.navbar-right %ul.nav.navbar-nav.navbar-right
= render "layouts/notifications" = render "layouts/notifications"
%li.hidden-xs{"data-toggle" => "tooltip", "data-placement" => "bottom", title: "Ask a question"} %li.hidden-xs{"data-toggle" => "tooltip", "data-placement" => "bottom", title: "Ask a question"}

View File

@ -8,7 +8,10 @@
.pull-left .pull-left
%img.img-rounded.answerbox--img{src: gravatar_url(comment.user)} %img.img-rounded.answerbox--img{src: gravatar_url(comment.user)}
.media-body.comments--body .media-body.comments--body
%h6.media-heading.answerbox--question-user= user_screen_name comment.user %h6.media-heading.answerbox--question-user
= user_screen_name comment.user
%span.text-muted{title: comment.created_at, data: { toggle: :tooltip, placement: :right }}
= "#{time_ago_in_words(comment.created_at)} ago"
- if comment.user == current_user - if comment.user == current_user
.pull-right .pull-right
.btn-group .btn-group

View File

@ -1,4 +1,4 @@
- provide(:title, "Moderation | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Moderation"))
= render 'moderation/moderation_nav' = render 'moderation/moderation_nav'
.container.j2-page .container.j2-page
.row .row

View File

@ -1,4 +1,4 @@
- provide(:title, "Notifications | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Notifications"))
= render 'notifications/notification_nav' = render 'notifications/notification_nav'
.container.j2-page .container.j2-page
= render 'notification_tabs' = render 'notification_tabs'

View File

@ -1,4 +1,4 @@
- provide(:title, "Public Timeline | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Public Timeline"))
= render 'static/mobile_nav' = render 'static/mobile_nav'
.container.j2-page .container.j2-page
.col-md-3.col-sm-3 .col-md-3.col-sm-3

View File

@ -1,35 +1,6 @@
- provide(:title, "#{@question.user.display_name.blank? ? "@#{@question.user.screen_name}'s" : "#{@question.user.display_name}'s"} question | #{APP_CONFIG['site_name']}") - provide(:title, question_title(@question))
.panel.panel-question = render 'shared/question_header', question: @question, hidden: false
.container = render 'shared/question_header', question: @question, hidden: true
.panel-body
.media.question-media
- unless @question.author_is_anonymous
%a.pull-left{href: show_user_profile_path(@question.user.screen_name)}
%img.img-rounded.answerbox--img{src: gravatar_url(@question.user)}
.media-body.question-body
- if user_signed_in?
.pull-right
.btn-group
%button.btn.btn-link.btn-sm.dropdown-toggle{data: { toggle: :dropdown }, aria: { expanded: :false }}
%span.caret
%ul.dropdown-menu.dropdown-menu-right{role: :menu}
- if current_user.mod? or @question.user == current_user
%li.text-danger
%a{href: '#', data: { action: 'ab-question-destroy', q_id: @question.id, redirect: if @question.author_is_anonymous? then "/" else show_user_questions_path(@question.user.screen_name) end }}
%i.fa.fa-trash-o
Delete Question
- unless @question.user == current_user
%li
%a{href: '#', data: { action: 'ab-question-report', q_id: @question.id }}
%i.fa.fa-exclamation-triangle
Report
%h6.text-muted.media-heading.answerbox--question-user
= user_screen_name @question.user, @question.author_is_anonymous
asked
%span{title: @question.created_at, data: { toggle: :tooltip, placement: :bottom }}
= time_ago_in_words(@question.created_at)
ago
%p.answerbox--question-text= @question.content
.container.question-page .container.question-page
/ TODO: make this pretty (it's currently C-c'd straight from shared/_answerbox) / TODO: make this pretty (it's currently C-c'd straight from shared/_answerbox)

View File

@ -1,4 +1,4 @@
- provide(:title, "Service Settings | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Service Settings"))
.container.j2-page .container.j2-page
= render 'user/settings_tabs' = render 'user/settings_tabs'
.col-md-9.col-xs-12.col-sm-9 .col-md-9.col-xs-12.col-sm-9

View File

@ -9,7 +9,10 @@
.pull-left .pull-left
%img.img-rounded.answerbox--img{src: gravatar_url(comment.user)} %img.img-rounded.answerbox--img{src: gravatar_url(comment.user)}
.media-body.comments--body .media-body.comments--body
%h6.media-heading.answerbox--question-user= user_screen_name comment.user %h6.media-heading.answerbox--question-user
= user_screen_name comment.user
%span.text-muted{title: comment.created_at, data: { toggle: :tooltip, placement: :right }}
= "#{time_ago_in_words(comment.created_at)} ago"
.pull-right .pull-right
%span.hidden-xs.text-muted %span.hidden-xs.text-muted
- unless user_signed_in? - unless user_signed_in?

View File

@ -1,6 +1,10 @@
.panel.panel-default.questionbox{data: { id: q.id }} .panel.panel-default.questionbox{data: { id: q.id }}
.panel-body .panel-body
.media .media
- if type == "discover"
.pull-left
%a{href: show_user_profile_path(q.user.screen_name)}
%img.answerbox--img{src: q.user.profile_picture.url(:medium)}
.media-body .media-body
- if user_signed_in? - if user_signed_in?
.pull-right .pull-right

View File

@ -0,0 +1,33 @@
.panel.panel-question{class: if hidden then 'question-hidden' end, tabindex: if hidden then '-1' end, aria: { hidden: if hidden then :true end }}
.container
.panel-body
.media.question-media
- unless question.author_is_anonymous
%a.pull-left{href: unless hidden then show_user_profile_path(question.user.screen_name) end}
%img.img-rounded.answerbox--img{src: gravatar_url(question.user)}
.media-body.question-body
- if user_signed_in?
.pull-right
.btn-group
%button.btn.btn-link.btn-sm.dropdown-toggle{data: { toggle: :dropdown }, aria: { expanded: :false }}
%span.caret
- unless hidden
%ul.dropdown-menu.dropdown-menu-right{role: :menu}
- if current_user.mod? or question.user == current_user
%li.text-danger
%a{href: '#', data: { action: 'ab-question-destroy', q_id: question.id, redirect: if question.author_is_anonymous? then "/" else show_user_questions_path(question.user.screen_name) end }}
%i.fa.fa-trash-o
Delete Question
- unless question.user == current_user
%li
%a{href: '#', data: { action: 'ab-question-report', q_id: question.id }}
%i.fa.fa-exclamation-triangle
Report
%h6.text-muted.media-heading.answerbox--question-user
= user_screen_name question.user, question.author_is_anonymous, !hidden
- unless hidden
asked
%span{title: question.created_at, data: { toggle: :tooltip, placement: :bottom }}
= time_ago_in_words(question.created_at)
ago
%p.answerbox--question-text= question.content

View File

@ -1,31 +1,38 @@
.jumbotron.j2-jumbo.text-center .jumbotron.j2-jumbo.text-center.particle-jumbotron
.container #particles
= render 'layouts/messages' .particle-content
%h1= APP_CONFIG['site_name'] .container
%p Ask questions, give answers and learn more about your friends. = render 'layouts/messages'
%p %h1= APP_CONFIG['site_name']
%a.btn.btn-primary.btn-lg{href: url_for(new_user_registration_path)} %p Ask questions, give answers and learn more about your friends.
Register now %p
%small %a.btn.btn-primary.btn-lg{href: url_for(new_user_registration_path)}
Already a member? Register now
= link_to 'Sign in', new_user_session_path %small
Already a member?
= link_to 'Sign in', new_user_session_path
.container-fluid .container-fluid
%h2.text-center Features
.row.text-center .row.text-center
.col-md-4.col-sm-4.col-xs-12 .col-md-4.col-sm-4.col-xs-12
%h3 .icon-showcase
%i.fa.fa-comments
%h3.heading-showcase
Ask and answer questions Ask and answer questions
%p %p
With With
= APP_CONFIG['site_name'] = APP_CONFIG['site_name']
you can ask people questions and answer questions from other users or unregistered people. Want to know something more? Keep the discussion ongoing in the comments! you can ask people questions and answer questions from other users or unregistered people. Want to know something more? Keep the discussion ongoing in the comments!
.col-md-4.col-sm-4.col-xs-12 .col-md-4.col-sm-4.col-xs-12
%h3 .icon-showcase
%i.fa.fa-users
%h3.heading-showcase
Follow users and get followed Follow users and get followed
%p %p
Following users allows you to get a personalized feed of all people you want to know more about. You can also send a question to all your followers at once! Following users allows you to get a personalized feed of all people you want to know more about. You can also send a question to all your followers at once!
.col-md-4.col-sm-4.col-xs-12 .col-md-4.col-sm-4.col-xs-12
%h3 .icon-showcase
%i.fa.fa-share-square-o
%h3.heading-showcase
Sharing to other networks Sharing to other networks
%p %p
Want to share your answer to a question so that more people read it? With a simple click on the answer button, your answer is shared wherever you want! Want to share your answer to a question so that more people read it? With a simple click on the answer button, your answer is shared wherever you want!

View File

@ -1,7 +1,9 @@
- provide(:title, "About | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("About"))
.jumbotron.j2-jumbo.text-center .jumbotron.j2-jumbo.text-center.particle-jumbotron
%h1= APP_CONFIG['site_name'] #particles
%p About our service, features and other information .particle-content
%h1= APP_CONFIG['site_name']
%p About our service, features and other information
.container .container
= render 'layouts/messages' = render 'layouts/messages'

View File

@ -1,7 +1,13 @@
- provide(:title, "Frequently Asked Questions | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Frequently Asked Questions"))
.jumbotron.j2-jumbo.text-center.particle-jumbotron
#particles
.particle-content
%h1 Frequently Asked Questions
%p
Everything you want to know about
= succeed '!' do
= APP_CONFIG['site_name']
.container .container
%h1.text-center Frequently Asked Questions
.panel-group{id: "accordion", role: "tablist", aria: {multiselectable: :true}} .panel-group{id: "accordion", role: "tablist", aria: {multiselectable: :true}}
.panel.panel-default .panel.panel-default
.panel-heading{id: "faqOne", role: "tab"} .panel-heading{id: "faqOne", role: "tab"}

View File

@ -1,4 +1,4 @@
- provide(:title, "Privacy Policy | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Privacy Policy"))
.container .container
.panel.panel-default .panel.panel-default
.panel-body .panel-body

View File

@ -1,4 +1,4 @@
- provide(:title, "Terms of Service | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Terms of Service"))
.container .container
.panel.panel-default .panel.panel-default
.panel-body .panel-body

View File

@ -1,4 +1,4 @@
- provide(:title, "Account Settings | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Account Settings"))
.container.j2-page .container.j2-page
= render 'user/settings_tabs' = render 'user/settings_tabs'
.col-md-9.col-xs-12.col-sm-9 .col-md-9.col-xs-12.col-sm-9

View File

@ -28,14 +28,15 @@
.profile--panel-badge.panel-badge-default .profile--panel-badge.panel-badge-default
Follows you Follows you
.panel-body .panel-body
- if @user.display_name.blank? .profile--panel-name
.profile--displayname - if @user.display_name.blank?
= @user.screen_name .profile--displayname
- else = @user.screen_name
.profile--displayname - else
= @user.display_name .profile--displayname
.profile--username = @user.display_name
= @user.screen_name .profile--username
= @user.screen_name
- unless @user.bio.blank? - unless @user.bio.blank?
%p.profile--text= markdown @user.bio %p.profile--text= markdown @user.bio
- unless @user.website.blank? - unless @user.website.blank?

View File

@ -1,4 +1,4 @@
.panel.panel-default.profile--panel .panel.panel-default.profile--panel#profile-stats
.panel-heading .panel-heading
%h3.panel-title Stats %h3.panel-title Stats
.panel-body .panel-body

View File

@ -1,4 +1,4 @@
- provide(:title, "Profile Settings | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Profile Settings"))
.container.j2-page .container.j2-page
= render 'settings_tabs' = render 'settings_tabs'
.col-md-9.col-xs-12.col-sm-9 .col-md-9.col-xs-12.col-sm-9
@ -9,7 +9,7 @@
= f.text_field :display_name, label: "Your name" = f.text_field :display_name, label: "Your name"
.media .media#profile-picture-media
.pull-left .pull-left
%img.img-rounded.profile--img{src: current_user.profile_picture.url(:medium)} %img.img-rounded.profile--img{src: current_user.profile_picture.url(:medium)}
.media-body .media-body
@ -26,7 +26,7 @@
%button#cropper-zoom-in.btn.btn-inverse{type: :button} %button#cropper-zoom-in.btn.btn-inverse{type: :button}
%i.fa.fa-search-plus %i.fa.fa-search-plus
.media .media#profile-header-media
.pull-left .pull-left
%img.img-rounded.header--img{src: current_user.profile_header.url(:mobile)} %img.img-rounded.header--img{src: current_user.profile_header.url(:mobile)}
.media-body .media-body

View File

@ -1,4 +1,4 @@
- provide(:title, "Privacy Settings | #{APP_CONFIG['site_name']}") - provide(:title, generate_title("Privacy Settings"))
.container.j2-page .container.j2-page
= render 'settings_tabs' = render 'settings_tabs'
.col-md-9.col-xs-12.col-sm-9 .col-md-9.col-xs-12.col-sm-9

View File

@ -1,4 +1,4 @@
- provide(:title, "#{@user.display_name.blank? ? "@#{@user.screen_name}'s" : "#{@user.display_name}'s"} questions | #{APP_CONFIG['site_name']}") - provide(:title, questions_title(@user))
.profile--header .profile--header
.container.j2-page .container.j2-page
.col-md-3.col-xs-12.col-sm-4.j2-col-reset .col-md-3.col-xs-12.col-sm-4.j2-col-reset
@ -9,7 +9,7 @@
%h1.visible-xs= @title %h1.visible-xs= @title
#questions #questions
- @questions.each do |q| - @questions.each do |q|
= render 'shared/question', q: q = render 'shared/question', q: q, type: nil
#pagination= will_paginate @questions, renderer: BootstrapPagination::Rails, page_links: false #pagination= will_paginate @questions, renderer: BootstrapPagination::Rails, page_links: false

View File

@ -1,9 +1,9 @@
- provide(:title, "#{@user.display_name.blank? ? "@#{@user.screen_name}" : "#{@user.display_name} (@#{@user.screen_name})"} | #{APP_CONFIG['site_name']}") - provide(:title, user_title(@user))
- no_header = unless @user.profile_header.exists? then "profile--no-header" else "" end - no_header = unless @user.profile_header.exists? then "profile--no-header" else "" end
#profile--header.hidden-xs{class: no_header} #profile--header{class: no_header}
%img.profile--header-img{src: @user.profile_header.url(:web)} %img.profile--header-img{src: @user.profile_header.url(:web)}
.container.j2-page.headerable{class: no_header} .container.j2-page.headerable{class: no_header}
.col-md-3.col-xs-12.col-sm-4.j2-col-reset #profile-info.col-md-3.col-xs-12.col-sm-4.j2-col-reset
= render 'user/profile_info' = render 'user/profile_info'
.hidden-xs= render 'shared/links' .hidden-xs= render 'shared/links'
.col-md-9.col-xs-12.col-sm-8.j2-col-reset .col-md-9.col-xs-12.col-sm-8.j2-col-reset

View File

@ -1,4 +1,4 @@
- provide(:title, "#{@user.display_name.blank? ? "@#{@user.screen_name}'s" : "#{@user.display_name}'s"} friends & followers | #{APP_CONFIG['site_name']}") - provide(:title, user_title(@user, "friends and followers"))
.profile--header .profile--header
.container.j2-page .container.j2-page
.col-md-3.col-xs-12.col-sm-4.j2-col-reset .col-md-3.col-xs-12.col-sm-4.j2-col-reset

View File

@ -90,6 +90,7 @@ Rails.application.routes.draw do
match '/unsubscribe', to: 'subscription#unsubscribe', via: :post, as: :unsubscribe_answer match '/unsubscribe', to: 'subscription#unsubscribe', via: :post, as: :unsubscribe_answer
end end
match '/discover', to: 'discover#index', via: :get, as: :discover
match '/public', to: 'public#index', via: :get, as: :public_timeline match '/public', to: 'public#index', via: :get, as: :public_timeline
match '/group/:group_name', to: 'group#index', via: :get, as: :group_timeline match '/group/:group_name', to: 'group#index', via: :get, as: :group_timeline

View File

@ -0,0 +1,453 @@
/*!
* Particleground
*
* @author Jonathan Nicol - @mrjnicol
* @version 1.1.0
* @description Creates a canvas based particle system background
*
* Inspired by http://requestlab.fr/ and http://disruptivebydesign.com/
*/
;(function(window, document) {
"use strict";
var pluginName = 'particleground';
// http://youmightnotneedjquery.com/#deep_extend
function extend(out) {
out = out || {};
for (var i = 1; i < arguments.length; i++) {
var obj = arguments[i];
if (!obj) continue;
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === 'object')
deepExtend(out[key], obj[key]);
else
out[key] = obj[key];
}
}
}
return out;
};
var $ = window.jQuery;
function Plugin(element, options) {
var canvasSupport = !!document.createElement('canvas').getContext;
var canvas;
var ctx;
var particles = [];
var raf;
var mouseX = 0;
var mouseY = 0;
var winW;
var winH;
var desktop = !navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|BB10|mobi|tablet|opera mini|nexus 7)/i);
var orientationSupport = !!window.DeviceOrientationEvent;
var tiltX = 0;
var pointerX;
var pointerY;
var tiltY = 0;
var paused = false;
options = extend({}, window[pluginName].defaults, options);
/**
* Init
*/
function init() {
if (!canvasSupport) { return; }
//Create canvas
canvas = document.createElement('canvas');
canvas.className = 'pg-canvas';
canvas.style.display = 'block';
element.insertBefore(canvas, element.firstChild);
ctx = canvas.getContext('2d');
styleCanvas();
// Create particles
var numParticles = Math.round((canvas.width * canvas.height) / options.density);
for (var i = 0; i < numParticles; i++) {
var p = new Particle();
p.setStackPos(i);
particles.push(p);
};
window.addEventListener('resize', function() {
resizeHandler();
}, false);
document.addEventListener('mousemove', function(e) {
mouseX = e.pageX;
mouseY = e.pageY;
}, false);
if (orientationSupport && !desktop) {
window.addEventListener('deviceorientation', function () {
// Contrain tilt range to [-30,30]
tiltY = Math.min(Math.max(-event.beta, -30), 30);
tiltX = Math.min(Math.max(-event.gamma, -30), 30);
}, true);
}
draw();
hook('onInit');
}
/**
* Style the canvas
*/
function styleCanvas() {
canvas.width = element.offsetWidth;
canvas.height = element.offsetHeight;
ctx.fillStyle = options.dotColor;
ctx.strokeStyle = options.lineColor;
ctx.lineWidth = options.lineWidth;
}
/**
* Draw particles
*/
function draw() {
if (!canvasSupport) { return; }
winW = window.innerWidth;
winH = window.innerHeight;
// Wipe canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Update particle positions
for (var i = 0; i < particles.length; i++) {
particles[i].updatePosition();
};
// Draw particles
for (var i = 0; i < particles.length; i++) {
particles[i].draw();
};
// Call this function next time screen is redrawn
if (!paused) {
raf = requestAnimationFrame(draw);
}
}
/**
* Add/remove particles.
*/
function resizeHandler() {
// Resize the canvas
styleCanvas();
var elWidth = element.offsetWidth;
var elHeight = element.offsetHeight;
// Remove particles that are outside the canvas
for (var i = particles.length - 1; i >= 0; i--) {
if (particles[i].position.x > elWidth || particles[i].position.y > elHeight) {
particles.splice(i, 1);
}
};
// Adjust particle density
var numParticles = Math.round((canvas.width * canvas.height) / options.density);
if (numParticles > particles.length) {
while (numParticles > particles.length) {
var p = new Particle();
particles.push(p);
}
} else if (numParticles < particles.length) {
particles.splice(numParticles);
}
// Re-index particles
for (i = particles.length - 1; i >= 0; i--) {
particles[i].setStackPos(i);
};
}
/**
* Pause particle system
*/
function pause() {
paused = true;
}
/**
* Start particle system
*/
function start() {
paused = false;
draw();
}
/**
* Particle
*/
function Particle() {
this.stackPos;
this.active = true;
this.layer = Math.ceil(Math.random() * 3);
this.parallaxOffsetX = 0;
this.parallaxOffsetY = 0;
// Initial particle position
this.position = {
x: Math.ceil(Math.random() * canvas.width),
y: Math.ceil(Math.random() * canvas.height)
}
// Random particle speed, within min and max values
this.speed = {}
switch (options.directionX) {
case 'left':
this.speed.x = +(-options.maxSpeedX + (Math.random() * options.maxSpeedX) - options.minSpeedX).toFixed(2);
break;
case 'right':
this.speed.x = +((Math.random() * options.maxSpeedX) + options.minSpeedX).toFixed(2);
break;
default:
this.speed.x = +((-options.maxSpeedX / 2) + (Math.random() * options.maxSpeedX)).toFixed(2);
this.speed.x += this.speed.x > 0 ? options.minSpeedX : -options.minSpeedX;
break;
}
switch (options.directionY) {
case 'up':
this.speed.y = +(-options.maxSpeedY + (Math.random() * options.maxSpeedY) - options.minSpeedY).toFixed(2);
break;
case 'down':
this.speed.y = +((Math.random() * options.maxSpeedY) + options.minSpeedY).toFixed(2);
break;
default:
this.speed.y = +((-options.maxSpeedY / 2) + (Math.random() * options.maxSpeedY)).toFixed(2);
this.speed.x += this.speed.y > 0 ? options.minSpeedY : -options.minSpeedY;
break;
}
}
/**
* Draw particle
*/
Particle.prototype.draw = function() {
// Draw circle
ctx.beginPath();
ctx.arc(this.position.x + this.parallaxOffsetX, this.position.y + this.parallaxOffsetY, options.particleRadius / 2, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
// Draw lines
ctx.beginPath();
// Iterate over all particles which are higher in the stack than this one
for (var i = particles.length - 1; i > this.stackPos; i--) {
var p2 = particles[i];
// Pythagorus theorum to get distance between two points
var a = this.position.x - p2.position.x
var b = this.position.y - p2.position.y
var dist = Math.sqrt((a * a) + (b * b)).toFixed(2);
// If the two particles are in proximity, join them
if (dist < options.proximity) {
ctx.moveTo(this.position.x + this.parallaxOffsetX, this.position.y + this.parallaxOffsetY);
if (options.curvedLines) {
ctx.quadraticCurveTo(Math.max(p2.position.x, p2.position.x), Math.min(p2.position.y, p2.position.y), p2.position.x + p2.parallaxOffsetX, p2.position.y + p2.parallaxOffsetY);
} else {
ctx.lineTo(p2.position.x + p2.parallaxOffsetX, p2.position.y + p2.parallaxOffsetY);
}
}
}
ctx.stroke();
ctx.closePath();
}
/**
* update particle position
*/
Particle.prototype.updatePosition = function() {
if (options.parallax) {
if (orientationSupport && !desktop) {
// Map tiltX range [-30,30] to range [0,winW]
var ratioX = (winW - 0) / (30 - -30);
pointerX = (tiltX - -30) * ratioX + 0;
// Map tiltY range [-30,30] to range [0,winH]
var ratioY = (winH - 0) / (30 - -30);
pointerY = (tiltY - -30) * ratioY + 0;
} else {
pointerX = mouseX;
pointerY = mouseY;
}
// Calculate parallax offsets
this.parallaxTargX = (pointerX - (winW / 2)) / (options.parallaxMultiplier * this.layer);
this.parallaxOffsetX += (this.parallaxTargX - this.parallaxOffsetX) / 10; // Easing equation
this.parallaxTargY = (pointerY - (winH / 2)) / (options.parallaxMultiplier * this.layer);
this.parallaxOffsetY += (this.parallaxTargY - this.parallaxOffsetY) / 10; // Easing equation
}
var elWidth = element.offsetWidth;
var elHeight = element.offsetHeight;
switch (options.directionX) {
case 'left':
if (this.position.x + this.speed.x + this.parallaxOffsetX < 0) {
this.position.x = elWidth - this.parallaxOffsetX;
}
break;
case 'right':
if (this.position.x + this.speed.x + this.parallaxOffsetX > elWidth) {
this.position.x = 0 - this.parallaxOffsetX;
}
break;
default:
// If particle has reached edge of canvas, reverse its direction
if (this.position.x + this.speed.x + this.parallaxOffsetX > elWidth || this.position.x + this.speed.x + this.parallaxOffsetX < 0) {
this.speed.x = -this.speed.x;
}
break;
}
switch (options.directionY) {
case 'up':
if (this.position.y + this.speed.y + this.parallaxOffsetY < 0) {
this.position.y = elHeight - this.parallaxOffsetY;
}
break;
case 'down':
if (this.position.y + this.speed.y + this.parallaxOffsetY > elHeight) {
this.position.y = 0 - this.parallaxOffsetY;
}
break;
default:
// If particle has reached edge of canvas, reverse its direction
if (this.position.y + this.speed.y + this.parallaxOffsetY > elHeight || this.position.y + this.speed.y + this.parallaxOffsetY < 0) {
this.speed.y = -this.speed.y;
}
break;
}
// Move particle
this.position.x += this.speed.x;
this.position.y += this.speed.y;
}
/**
* Setter: particle stacking position
*/
Particle.prototype.setStackPos = function(i) {
this.stackPos = i;
}
function option (key, val) {
if (val) {
options[key] = val;
} else {
return options[key];
}
}
function destroy() {
console.log('destroy');
canvas.parentNode.removeChild(canvas);
hook('onDestroy');
if ($) {
$(element).removeData('plugin_' + pluginName);
}
}
function hook(hookName) {
if (options[hookName] !== undefined) {
options[hookName].call(element);
}
}
init();
return {
option: option,
destroy: destroy,
start: start,
pause: pause
};
}
window[pluginName] = function(elem, options) {
return new Plugin(elem, options);
};
window[pluginName].defaults = {
minSpeedX: 0.1,
maxSpeedX: 0.7,
minSpeedY: 0.1,
maxSpeedY: 0.7,
directionX: 'center', // 'center', 'left' or 'right'. 'center' = dots bounce off edges
directionY: 'center', // 'center', 'up' or 'down'. 'center' = dots bounce off edges
density: 10000, // How many particles will be generated: one particle every n pixels
dotColor: '#666666',
lineColor: '#666666',
particleRadius: 7, // Dot size
lineWidth: 1,
curvedLines: false,
proximity: 100, // How close two dots need to be before they join
parallax: true,
parallaxMultiplier: 5, // The lower the number, the more extreme the parallax effect
onInit: function() {},
onDestroy: function() {}
};
// nothing wrong with hooking into jQuery if it's there...
if ($) {
$.fn[pluginName] = function(options) {
if (typeof arguments[0] === 'string') {
var methodName = arguments[0];
var args = Array.prototype.slice.call(arguments, 1);
var returnVal;
this.each(function() {
if ($.data(this, 'plugin_' + pluginName) && typeof $.data(this, 'plugin_' + pluginName)[methodName] === 'function') {
returnVal = $.data(this, 'plugin_' + pluginName)[methodName].apply(this, args);
}
});
if (returnVal !== undefined){
return returnVal;
} else {
return this;
}
} else if (typeof options === "object" || !options) {
return this.each(function() {
if (!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName, new Plugin(this, options));
}
});
}
};
}
})(window, document);
/**
* requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
* @see: http://paulirish.com/2011/requestanimationframe-for-smart-animating/
* @see: http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
* @license: MIT license
*/
(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
|| window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());