From 2ffcf9c72caf90465765db9143a7c5cbd6cefd78 Mon Sep 17 00:00:00 2001 From: Mateusz Palyz Date: Tue, 19 May 2015 15:35:58 +0200 Subject: [PATCH 01/16] add font awesome --- Gemfile | 1 + Gemfile.lock | 3 +++ app/assets/stylesheets/application.css.scss | 2 ++ 3 files changed, 6 insertions(+) diff --git a/Gemfile b/Gemfile index 13d32d1d..010bd089 100644 --- a/Gemfile +++ b/Gemfile @@ -44,6 +44,7 @@ gem "newrelic_rpm", "~> 3.9.6" gem "draper", "~> 0.11.1" gem "open_uri_redirections", "~> 0.1.4" gem "rack-timeout", "~> 0.1.0" +gem "font-awesome-rails" # background job queue gem "delayed_job", :git => "git://github.com/collectiveidea/delayed_job.git", :tag => "v2.1.4" diff --git a/Gemfile.lock b/Gemfile.lock index 8a46b313..5a008817 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -110,6 +110,8 @@ GEM faraday (0.9.0) multipart-post (>= 1.2, < 3) ffi (1.9.3) + font-awesome-rails (4.3.0.0) + railties (>= 3.2, < 5.0) fssm (0.2.10) haml (3.1.8) haml-rails (0.3.5) @@ -302,6 +304,7 @@ DEPENDENCIES draper (~> 0.11.1) exceptional (~> 2.0.32) fabrication (~> 1.2.0) + font-awesome-rails haml (~> 3.1.4) haml-rails (~> 0.3.4) i18n (~> 0.6.0) diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss index 08ff3256..98a4108e 100644 --- a/app/assets/stylesheets/application.css.scss +++ b/app/assets/stylesheets/application.css.scss @@ -15,3 +15,5 @@ @import "lib/base"; @import "partials/flash"; + +@import "font-awesome"; From 435a10e47d594769846d437519730f873f6a2c55 Mon Sep 17 00:00:00 2001 From: Mateusz Palyz Date: Tue, 19 May 2015 15:38:45 +0200 Subject: [PATCH 02/16] add hidden css class --- app/assets/stylesheets/content.scss.erb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/stylesheets/content.scss.erb b/app/assets/stylesheets/content.scss.erb index 29ce2cbc..1567371b 100644 --- a/app/assets/stylesheets/content.scss.erb +++ b/app/assets/stylesheets/content.scss.erb @@ -10,6 +10,10 @@ } } +.hidden { + display: none; +} + /* ****************************** */ /* Updates Navigation */ /* ****************************** */ From d4ac393e9827beb6e3944659dcc2e928490950f5 Mon Sep 17 00:00:00 2001 From: Mateusz Palyz Date: Tue, 19 May 2015 15:41:36 +0200 Subject: [PATCH 03/16] move logic choosing correct update to another method, add respond to js block --- app/controllers/updates_controller.rb | 31 ++++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/app/controllers/updates_controller.rb b/app/controllers/updates_controller.rb index 7e4b0571..e254d313 100644 --- a/app/controllers/updates_controller.rb +++ b/app/controllers/updates_controller.rb @@ -5,27 +5,35 @@ class UpdatesController < ApplicationController def index @title = "updates" @list_class = "all" + prepare_updates(Update) respond_to do |format| - format.html { render_index(Update) } + format.html { render :index, :layout => show_layout? } format.json { - @updates = Update - set_pagination render :json => @updates.map{ |u| UpdateJsonDecorator.decorate(u) } } + format.js end end def timeline if current_user @list_class = "friends" - render_index(current_user.timeline) + prepare_updates(current_user.timeline) + respond_to do |format| + format.html { render :index, :layout => show_layout? } + format.js { render :index } + end end end def replies @list_class = "mentions" - render_index(current_user.at_replies) + prepare_updates(current_user.at_replies) + respond_to do |format| + format.html { render :index, :layout => show_layout? } + format.js { render :index } + end end def export @@ -93,20 +101,13 @@ def destroy protected - # Manage page state - def set_pagination + # Prepare correct updates depending on request type + def prepare_updates(updates) set_params_page - @updates = @updates.paginate(:page => params[:page], :per_page => params[:per_page], :order => :created_at.desc) + @updates = updates.paginate(:page => params[:page], :per_page => params[:per_page], :order => :created_at.desc) set_pagination_buttons(@updates) end - # Render correct haml depending on request type - def render_index(updates) - @updates = updates - set_pagination - render :index, :layout => show_layout? - end - def process_params @update_id, @update_text = "", "" From 3bd15c43bb142566d04442f8f99a73104dab22c8 Mon Sep 17 00:00:00 2001 From: Mateusz Palyz Date: Tue, 19 May 2015 15:42:41 +0200 Subject: [PATCH 04/16] add respond to js for user's profile page --- app/controllers/users_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 1aa6908b..72a2fd9f 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -44,6 +44,7 @@ def show format.json { render :json => @updates.map{ |u| UpdateJsonDecorator.decorate(u) } } + format.js { render 'updates/index', locals: { no_highlight: true } } end end From 204ac8af45026b8655130f25fd26ed13fcafae28 Mon Sep 17 00:00:00 2001 From: Mateusz Palyz Date: Tue, 19 May 2015 15:46:38 +0200 Subject: [PATCH 05/16] add infinite_scroll option to user model, scrolling preference is set per-user basis --- app/models/user.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/user.rb b/app/models/user.rb index 4704062f..e8cef133 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -42,6 +42,8 @@ def admin? # Global preference set via user's profile controlling the state of the Post to Twitter checkbox key :always_send_to_twitter, Integer, :default => 1 + key :infinite_scroll, Boolean, default: true + validate :email_already_confirmed validates_uniqueness_of :username, :allow_nil => :true, @@ -355,6 +357,8 @@ def update_profile!(params) self.always_send_to_twitter = params[:user] && params[:user][:always_send_to_twitter].to_i + self.infinite_scroll = params[:user][:infinite_scroll] + # I can't figure out how to use a real rails validator to confirm that # password matches password_confirm, since these two attributes are # virtual and we only want to check this in this particular case of From 09fa6b706f3b32766753e5460aba04445c4ddb80 Mon Sep 17 00:00:00 2001 From: Mateusz Palyz Date: Tue, 19 May 2015 16:24:59 +0200 Subject: [PATCH 06/16] move some code from updates list into partial, add infinite_scroll_toggle variable --- app/views/updates/_list.html.haml | 50 ++++------------------------- app/views/updates/_update.html.haml | 43 +++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 44 deletions(-) create mode 100644 app/views/updates/_update.html.haml diff --git a/app/views/updates/_list.html.haml b/app/views/updates/_list.html.haml index 3dd5cbd3..870b7419 100644 --- a/app/views/updates/_list.html.haml +++ b/app/views/updates/_list.html.haml @@ -1,51 +1,13 @@ - unless defined?(id) - id = (request.path_info.gsub("/", "_")[1..-1]) +- if logged_in? + - infinite_scroll_toggle = current_user.infinite_scroll ? "updates-scroll" : "" +- else + - infinite_scroll_toggle = controller_name == "static" ? "" : "updates-scroll" #messages - %ul.updates{:class => "#{list_class}#{(controller.controller_name == "updates" ? " has-update-form" : "")}", :id => id} + %ul.updates{:class => "#{list_class}#{(controller.controller_name == "updates" ? " has-update-form #{infinite_scroll_toggle}" : " #{infinite_scroll_toggle}")}", :id => id} - updates.each do |update| - - unless defined?(no_highlight) and no_highlight - - mine = current_user.nil? ? false : (update.author.user == current_user) - - mentioned = current_user.nil? ? false : update.mentioned?(current_user.username) - %li.update.hentry.message{:class => (mentioned ? "mention " : "") + (mine ? "mine " : ""), :id => "update-#{update.id}", "data-id" => update.id, "data-name" => update.author ? update.author.fully_qualified_name : ""} - - if update.author - .author.vcard - %a.url{:href => update.author.url, :rel => "user"} - = AuthorDecorator.decorate(update.author).avatar - %span.fn - %a.url{:href => update.author.url} - = update.author.display_name - (#{update.author.username}) - .entry-content - %span.message-text - != update.to_html - - .info - = TimeDecorator.decorate(update).permalink - - - if !update.referral.nil? - %span.in-reply - %a{:href => "/updates/#{update.referral.id}"} - in reply to - - if update.referral.author - %span.name= update.referral.author.username - - else - an update - - elsif !update.referral_url.nil? - %span.in-reply - %a{:href => update.referral_url} - in reply to - - .actions - -# when @timeline is true, this is a list on the user's page - -unless current_user.nil? or (current_user.author.id == update.author.id) - %a.share{:href => (controller.controller_name == "updates" ? "" : "/") + "?share=#{update.id}"} share - | - %a.reply{:href => (controller.controller_name == "updates" ? "" : "/") + "?reply=#{update.id}"} reply - - - if current_user and update.author.id == current_user.author.id - = form_tag "/updates/#{update.id}" do - %input{:type => "hidden", :name => "_method", :value => "delete"} - = submit_tag "I Regret This", :class => "remove-update", :confirm => t(:remove_update, :scope => :confirms) + = render update, no_highlight: defined?(no_highlight) != render :partial => "shared/pagination" diff --git a/app/views/updates/_update.html.haml b/app/views/updates/_update.html.haml new file mode 100644 index 00000000..464119b7 --- /dev/null +++ b/app/views/updates/_update.html.haml @@ -0,0 +1,43 @@ +- unless defined?(no_highlight) and no_highlight + - mine = current_user.nil? ? false : (update.author.user == current_user) + - mentioned = current_user.nil? ? false : update.mentioned?(current_user.username) +%li.update.hentry.message{:class => (mentioned ? "mention " : "") + (mine ? "mine " : ""), :id => "update-#{update.id}", "data-id" => update.id, "data-name" => update.author ? update.author.fully_qualified_name : ""} + - if update.author + .author.vcard + %a.url{:href => update.author.url, :rel => "user"} + = AuthorDecorator.decorate(update.author).avatar + %span.fn + %a.url{:href => update.author.url} + = update.author.display_name + (#{update.author.username}) + .entry-content + %span.message-text + != update.to_html + + .info + = TimeDecorator.decorate(update).permalink + + - if !update.referral.nil? + %span.in-reply + %a{:href => "/updates/#{update.referral.id}"} + in reply to + - if update.referral.author + %span.name= update.referral.author.username + - else + an update + - elsif !update.referral_url.nil? + %span.in-reply + %a{:href => update.referral_url} + in reply to + + .actions + -# when @timeline is true, this is a list on the user's page + -unless current_user.nil? or (current_user.author.id == update.author.id) + %a.share{:href => (controller.controller_name == "updates" ? "" : "/") + "?share=#{update.id}"} share + | + %a.reply{:href => (controller.controller_name == "updates" ? "" : "/") + "?reply=#{update.id}"} reply + + - if current_user and update.author.id == current_user.author.id + = form_tag "/updates/#{update.id}" do + %input{:type => "hidden", :name => "_method", :value => "delete"} + = submit_tag "I Regret This", :class => "remove-update", :confirm => t(:remove_update, :scope => :confirms) From f395c3c04e4e7b78cb0c586d1fc2df94de112a14 Mon Sep 17 00:00:00 2001 From: Mateusz Palyz Date: Tue, 19 May 2015 16:26:28 +0200 Subject: [PATCH 07/16] add checkbox for setting infinite scroll on/off --- app/views/users/edit.haml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/views/users/edit.haml b/app/views/users/edit.haml index 4a6ffefa..41e806af 100644 --- a/app/views/users/edit.haml +++ b/app/views/users/edit.haml @@ -20,6 +20,14 @@ = render :partial => "shared/field", :locals => {:obj => @user.author, :attr => :website, :params => params} = render :partial => "shared/field", :locals => {:obj => @user.author, :attr => :bio, :as => :text, :params => params} + .form-section.infinite_scroll_toggle.hidden + = f.check_box :infinite_scroll, class: 'hidden' + = label_tag '', "Updates' feed infinite scroll" + - if current_user.infinite_scroll + %span.fa.fa-toggle-on.fa-lg.infinite-scroll-on + - else + %span.fa.fa-toggle-off.fa-lg.inifinite-scroll-off + - if @user.twitter? .form-section.preferences .section-label From ced33273449ecf2f7c40699628f5b576cc46ab35 Mon Sep 17 00:00:00 2001 From: Mateusz Palyz Date: Tue, 19 May 2015 16:27:26 +0200 Subject: [PATCH 08/16] handle infinite scroll switch --- app/assets/javascripts/user_edit.js.coffee | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 app/assets/javascripts/user_edit.js.coffee diff --git a/app/assets/javascripts/user_edit.js.coffee b/app/assets/javascripts/user_edit.js.coffee new file mode 100644 index 00000000..adf46af8 --- /dev/null +++ b/app/assets/javascripts/user_edit.js.coffee @@ -0,0 +1,16 @@ +jQuery -> + if $('#profile').length + container = $('.infinite_scroll_toggle') + # if javascript is not supported, infinite scroll option is not displayed + container.removeClass('hidden') + checkbox = $('#user_infinite_scroll') + + container.on 'click', '.fa-toggle-on', (e) => + toggleIcon = $(e.target) + toggleIcon.removeClass('fa-toggle-on').addClass('fa-toggle-off') + checkbox.attr('checked', false) + + container.on 'click', '.fa-toggle-off', (e) => + toggleIcon = $(e.target) + toggleIcon.removeClass('fa-toggle-off').addClass('fa-toggle-on') + checkbox.attr('checked', true) From c065f0d32a916222600ff55774f96744f2f8a43b Mon Sep 17 00:00:00 2001 From: Mateusz Palyz Date: Tue, 19 May 2015 16:36:00 +0200 Subject: [PATCH 09/16] add info about infinite scroll to pagination partial --- app/views/shared/_pagination.haml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/views/shared/_pagination.haml b/app/views/shared/_pagination.haml index 19e67312..e0c6b037 100644 --- a/app/views/shared/_pagination.haml +++ b/app/views/shared/_pagination.haml @@ -1,4 +1,19 @@ %nav.pagination + + .loading-info.hidden + .popover.scroll-help-popover.hidden + %b TIP: + You can disable infinite scroll in your + - if logged_in? + != "#{link_to 'profile settings', edit_user_path(current_user)}." + - else + profile settings. + .arrow + %p + Keep scrolling to load more data + %span.fa.fa-question-circle.fa-lg.scroll-help + %i.fa.fa-hand-o-down.fa-lg + - unless @previous_page.nil? %a.button{:href => @previous_page, :id => "prev_button", :rel => "previous"} « Previous From 538610c5c4740628b24335e015eee1d42d3fa926 Mon Sep 17 00:00:00 2001 From: Mateusz Palyz Date: Tue, 19 May 2015 16:36:56 +0200 Subject: [PATCH 10/16] handle infinite scroll and info popover --- app/assets/javascripts/updates.js.coffee | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 app/assets/javascripts/updates.js.coffee diff --git a/app/assets/javascripts/updates.js.coffee b/app/assets/javascripts/updates.js.coffee new file mode 100644 index 00000000..7c7bab65 --- /dev/null +++ b/app/assets/javascripts/updates.js.coffee @@ -0,0 +1,25 @@ +jQuery -> + if $('.updates-scroll').length + $(window).scroll -> + next_button = $('#next_button') + prev_button = $('#prev_button') + url = next_button.attr('href') + + if (next_button || prev_button) && $(window).scrollTop() > $(document).height() - $(window).height() - 150 + next_button.addClass('hidden') + prev_button.addClass('hidden') + $('.loading-info').removeClass('hidden') + if url && $(window).scrollTop() > $(document).height() - $(window).height() - 2 + $('.pagination').html("
") + $.getScript(url) + $(window).scroll() + + popover = $('.scroll-help-popover') + $('.scroll-help').on 'click', (e) -> + e.stopPropagation() + if popover.hasClass('hidden') + popover.removeClass('hidden') + $(document).on 'click', -> + popover.addClass('hidden') + else + popover.addClass('hidden') From 20619585edb4e338218e5c0e94f12fc0f1bfd9d3 Mon Sep 17 00:00:00 2001 From: Mateusz Palyz Date: Tue, 19 May 2015 16:37:56 +0200 Subject: [PATCH 11/16] load correct data into infinite scroll, handle info popover for loaded data --- app/views/updates/index.js.erb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 app/views/updates/index.js.erb diff --git a/app/views/updates/index.js.erb b/app/views/updates/index.js.erb new file mode 100644 index 00000000..b661adda --- /dev/null +++ b/app/views/updates/index.js.erb @@ -0,0 +1,21 @@ +$('.updates-scroll').append('<%= j render @updates, no_highlight: defined?(no_highlight) %>'); +<% if @updates.next_page %> + $('.pagination').replaceWith('<%= j raw render "shared/pagination" %>'); +<% else %> + $('.pagination').remove(); +<% end %> + +var popover; +popover = $('.scroll-help-popover'); + +$('.scroll-help').on('click', function(e) { + e.stopPropagation(); + if (popover.hasClass('hidden')) { + popover.removeClass('hidden'); + return $(document).on('click', function() { + return popover.addClass('hidden'); + }); + } else { + return popover.addClass('hidden'); + } +}); From b80fb780be8f2cfd527c0827eb4ac028a410ea81 Mon Sep 17 00:00:00 2001 From: Mateusz Palyz Date: Tue, 19 May 2015 16:38:53 +0200 Subject: [PATCH 12/16] style infinite scroll switch --- app/assets/stylesheets/content.scss.erb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/assets/stylesheets/content.scss.erb b/app/assets/stylesheets/content.scss.erb index 1567371b..c8ae3327 100644 --- a/app/assets/stylesheets/content.scss.erb +++ b/app/assets/stylesheets/content.scss.erb @@ -411,6 +411,13 @@ border-color: #522; } +.infinite_scroll_toggle { + span.fa { + margin-left: 9px; + cursor: pointer; + } +} + /* ****************************** */ /* Sidebar */ /* ****************************** */ From 6faf63c4547eb0d9bd725c8d10f10fb38c67cf95 Mon Sep 17 00:00:00 2001 From: Mateusz Palyz Date: Tue, 19 May 2015 16:39:43 +0200 Subject: [PATCH 13/16] style infinite scroll indicators --- app/assets/stylesheets/layout.scss.erb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/assets/stylesheets/layout.scss.erb b/app/assets/stylesheets/layout.scss.erb index 40bd4b87..941bb32b 100644 --- a/app/assets/stylesheets/layout.scss.erb +++ b/app/assets/stylesheets/layout.scss.erb @@ -93,6 +93,20 @@ h2.title { margin-top: 1em; } + .loading-info { + text-align: center; + padding-top: 7px; + p { + margin: 0; + span { + padding-top: 1px; + float: right; + margin-left: -20px; + cursor: pointer; + } + } + } + #next_button { float: right; margin-right: 0.5em; From 2beeb71a039c80bf2c727c854f79fceb36cbd685 Mon Sep 17 00:00:00 2001 From: Mateusz Palyz Date: Tue, 19 May 2015 16:40:08 +0200 Subject: [PATCH 14/16] style popover --- app/assets/stylesheets/layout.scss.erb | 47 ++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/app/assets/stylesheets/layout.scss.erb b/app/assets/stylesheets/layout.scss.erb index 941bb32b..e5d2876f 100644 --- a/app/assets/stylesheets/layout.scss.erb +++ b/app/assets/stylesheets/layout.scss.erb @@ -116,6 +116,53 @@ h2.title { margin-left: 0.5em; } } + + .popover { + position: absolute; + z-index: 1000; + width: 230px; + padding: 5px; + border: 1px solid rgba(0,0,0,.2); + border-radius: 6px; + box-shadow: 0 5px 10px rgba(0,0,0,.2); + background-color: #fff; + + .arrow { + + &, + &:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + } + + border-width: 11px; + left: 50%; + margin-left: -11px; + border-bottom-width: 0; + border-top-color: #999; + border-top-color: rgba(0,0,0,.25); + bottom: -11px; + + &:after { + border-width: 10px; + content: ""; + content: " "; + bottom: 1px; + margin-left: -10px; + border-bottom-width: 0; + border-top-color: #fff; + } + } + } + + .scroll-help-popover { + right: -102px; + bottom: 60px; + } } /* *******************************/ From a8979cd21629d826a9031239d399acfbb37619fe Mon Sep 17 00:00:00 2001 From: Mateusz Palyz Date: Tue, 19 May 2015 16:58:20 +0200 Subject: [PATCH 15/16] update infinite_scroll option only if it is present in the params --- app/models/user.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/user.rb b/app/models/user.rb index e8cef133..c9385672 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -357,7 +357,7 @@ def update_profile!(params) self.always_send_to_twitter = params[:user] && params[:user][:always_send_to_twitter].to_i - self.infinite_scroll = params[:user][:infinite_scroll] + self.infinite_scroll = params[:user][:infinite_scroll] if params[:user] && params[:user][:infinite_scroll] # I can't figure out how to use a real rails validator to confirm that # password matches password_confirm, since these two attributes are From de17a6da2dc2b36b805f5d2e9c63b0ebf1781147 Mon Sep 17 00:00:00 2001 From: Mateusz Palyz Date: Thu, 21 May 2015 16:45:52 +0200 Subject: [PATCH 16/16] fix ininite scroll info showing up when not necessary --- app/assets/javascripts/updates.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/updates.js.coffee b/app/assets/javascripts/updates.js.coffee index 7c7bab65..35106ca0 100644 --- a/app/assets/javascripts/updates.js.coffee +++ b/app/assets/javascripts/updates.js.coffee @@ -5,7 +5,7 @@ jQuery -> prev_button = $('#prev_button') url = next_button.attr('href') - if (next_button || prev_button) && $(window).scrollTop() > $(document).height() - $(window).height() - 150 + if (next_button.length || prev_button.length) && $(window).scrollTop() > $(document).height() - $(window).height() - 150 next_button.addClass('hidden') prev_button.addClass('hidden') $('.loading-info').removeClass('hidden')