From f6ceafb710a24fd0603bd85c9c89eebd12d9a847 Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 09:39:47 +0100 Subject: [PATCH 01/25] added jquery.Jcrop --- Gemfile | 1 + Gemfile.lock | 2 ++ app/assets/javascripts/application.js.erb.coffee | 1 + app/assets/stylesheets/application.css.scss | 1 + 4 files changed, 5 insertions(+) diff --git a/Gemfile b/Gemfile index dd1e8e80..a1383501 100644 --- a/Gemfile +++ b/Gemfile @@ -29,6 +29,7 @@ gem 'font-kit-rails' gem 'nprogress-rails' gem 'font-awesome-rails', '~> 4.2.0.0' gem 'rails-assets-growl' +gem 'jcrop-rails-v2' gem 'ruby-progressbar' diff --git a/Gemfile.lock b/Gemfile.lock index 73345c77..d098d572 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -123,6 +123,7 @@ GEM jbuilder (2.2.5) activesupport (>= 3.0.0, < 5) multi_json (~> 1.2) + jcrop-rails-v2 (0.9.12.3) jquery-rails (3.1.2) railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) @@ -348,6 +349,7 @@ DEPENDENCIES haml http_accept_language jbuilder (~> 2.2.4) + jcrop-rails-v2 jquery-rails jquery-turbolinks mysql2 diff --git a/app/assets/javascripts/application.js.erb.coffee b/app/assets/javascripts/application.js.erb.coffee index f37ea0b7..fda6f467 100644 --- a/app/assets/javascripts/application.js.erb.coffee +++ b/app/assets/javascripts/application.js.erb.coffee @@ -7,6 +7,7 @@ #= require nprogress-turbolinks #= require growl #= require cheet +#= require jquery.Jcrop #= require_tree . NProgress.configure diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss index f929ab0d..5c522e6b 100644 --- a/app/assets/stylesheets/application.css.scss +++ b/app/assets/stylesheets/application.css.scss @@ -1,6 +1,7 @@ /* *= require rails_bootstrap_forms *= require growl + *= require jquery.Jcrop *= require_self */ From 6a6e94f6a3607ec1a961bbdf879e0c0a634dc74f Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 09:58:40 +0100 Subject: [PATCH 02/25] added Paperclip --- Gemfile | 1 + Gemfile.lock | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/Gemfile b/Gemfile index a1383501..ed6e04f4 100644 --- a/Gemfile +++ b/Gemfile @@ -30,6 +30,7 @@ gem 'nprogress-rails' gem 'font-awesome-rails', '~> 4.2.0.0' gem 'rails-assets-growl' gem 'jcrop-rails-v2' +gem "paperclip", "~> 4.2" gem 'ruby-progressbar' diff --git a/Gemfile.lock b/Gemfile.lock index d098d572..e33fc483 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -67,7 +67,11 @@ GEM xpath (~> 2.0) celluloid (0.16.0) timers (~> 4.0.0) + climate_control (0.0.3) + activesupport (>= 3.0) cliver (0.3.2) + cocaine (0.5.5) + climate_control (>= 0.0.3, < 1.0) coffee-rails (4.1.0) coffee-script (>= 2.2.0) railties (>= 4.0.0, < 5.0) @@ -168,6 +172,11 @@ GEM multi_json (~> 1.3) omniauth-oauth (~> 1.0) orm_adapter (0.5.0) + paperclip (4.2.1) + activemodel (>= 3.0.0) + activesupport (>= 3.0.0) + cocaine (~> 0.5.3) + mime-types pg (0.17.1) poltergeist (1.5.1) capybara (~> 2.1) @@ -356,6 +365,7 @@ DEPENDENCIES nprogress-rails omniauth omniauth-twitter + paperclip (~> 4.2) pg poltergeist questiongenerator! From f5917277fa0331b776dd325c8dbab17d1dfb0c8f Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 10:17:48 +0100 Subject: [PATCH 03/25] added default avatar --- public/images/medium/no_avatar.png | Bin 0 -> 8753 bytes public/images/original/no_avatar.png | Bin 0 -> 3091 bytes public/images/thumb/no_avatar.png | Bin 0 -> 1910 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/images/medium/no_avatar.png create mode 100644 public/images/original/no_avatar.png create mode 100644 public/images/thumb/no_avatar.png diff --git a/public/images/medium/no_avatar.png b/public/images/medium/no_avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..b4aa610f7232786b5879ac5e33d945270d76eb0b GIT binary patch literal 8753 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

U1Ah3q$xPB4e5hb@why~n;h;pY)^RId% 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 N5j(6irpCrU@qf+1x;X#< literal 0 HcmV?d00001 diff --git a/public/images/thumb/no_avatar.png b/public/images/thumb/no_avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..b7603d67019d6bf7d3a0de5aa09e62e55030ab39 GIT binary patch literal 1910 zcmV-+2Z{KJP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00002 zVoOIv0RM-N%)bBt010qNS#tmY3ljhU3ljkVnw%H_00w+XL_t(o!|j-PY!p=-$G62O zloGpplOnVD}6!-_PCURy^Rg`x`Pvyfyy%6^@nI?<2TOXa=G_Hp^b#Vytg9+Aj<}f5nGi* zQV2o>s)NPR7wB<&_-}=co|+9LkK=*FzHZIHuHSyHJX6=^zn^tq-b_My(KT9ut}_%t zV9e%cn+Vm&go2`R}O=V3r7ynY})T^BYr$&APiwc5(&5(3DOoazNYWV0ZmUnE*GS~p^z z;KacmO+e=+K0pg+6S6%?nk@uMFnBd0%Vgb?Q6?VfxbAUl0J_QvNGDHQgh>dDv;vee zH;FW@nX*LEiXfHvN(Mq{0ubSA<~EoodAloV{qRcToHq8c+(Ev>`<0BU8^@3WvWBd7bb%k7ugJ9Oh zN@a&YvI!w9iPwt*h^*@fJbl@OcW5adr2WwC9###=x=-@~i#5t=$lyH%R=GPF zd~}pv3JBVD>h}k#K#ps4@KXvSq#nd=Vrt|7#N$Nz+PL)9nPTQ)D~mEs7P z*GL+{z&?RQR^0qg;?mOPlu`MmRjoa}YQTp_`EUUf0sR&tEXD<^R=k_gcNb8&`$TgW z8yv{G{lgt!VbB0o_M%%|wdY zQ#-h&{edi7UkJ1UVL{HDls5qpXLrOc?Xp?8&dMCev2?Mv>lj_C7yzdhT5QaZ?Uda=A=MGKibC zXiDT#+2_odk-A4Cp4Q`lqJ4vipyT4T`l|1X8IrFErNTZV*bs&l)91YStT;>|y>QIq z5l_6m62p`#6re4i*=d2sZ&m<$?rjjwh~?uRdnSnzA57klh)ztNaSdGi$tY|_1y z3j4MM1Y}%vbcz(jw8%G1w#1|i5(Zj*Gg%3Ew@3sc%xEP02*lcS90kVpFQrbox+UcP)bT=skcA+H{$#VLI~tCp#$4b6)S8Mq~+P|YCHvCPi^%!Idwi^ z&)>dnYi{VkW@qzW(Vod0q>!{y`S}GKLylpuv!ia0sEu+A9JE-fk$<#RpS*s+jwbeO zj^rYpM|$<(Sq77}kW%GAzgM%C&h`^qv&CyP5Dyn|sA42V5*m2^3SFMghLaBIB0(TT z+Qb=#a15a$dI&BHM?k4J6DW4Z%M+If9W3D4nI*_d&8y*%mdOoH77*qn@ zI$8{5V9cmT!otHNHMklK*m0>?9s|_cNntwO$mRbI$hqrE@ zuI2a$0qCkM${C{10f2veP7jS20La}bC59Jx>+2HjPwrZPo!5>GuR_kbYlwLc0A!nv zXAiGJcij$^xt<807*qoM6N<$g2i%W3IG5A literal 0 HcmV?d00001 From cf3933271a39c0d3c5310a3c80e50323d6886c10 Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 10:18:12 +0100 Subject: [PATCH 04/25] added profile_picture to users --- app/models/user.rb | 3 ++ ...add_attachment_profile_picture_to_users.rb | 11 ++++++ db/schema.rb | 36 ++++++++++--------- 3 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 db/migrate/20141229085904_add_attachment_profile_picture_to_users.rb diff --git a/app/models/user.rb b/app/models/user.rb index 4a805a4d..b79c6d52 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -40,6 +40,9 @@ class User < ActiveRecord::Base # validates :website, format: { with: WEBSITE_REGEX } + has_attached_file :profile_picture, styles: { medium: "256x256>", thumb: "80x80>" }, default_url: "/images/:style/no_avatar.png" + validates_attachment_content_type :profile_picture, :content_type => /\Aimage\/.*\Z/ + before_save do self.display_name = 'WRYYYYYYYY' if display_name == 'Dio Brando' self.website = if website.match %r{\Ahttps?://} diff --git a/db/migrate/20141229085904_add_attachment_profile_picture_to_users.rb b/db/migrate/20141229085904_add_attachment_profile_picture_to_users.rb new file mode 100644 index 00000000..5191d385 --- /dev/null +++ b/db/migrate/20141229085904_add_attachment_profile_picture_to_users.rb @@ -0,0 +1,11 @@ +class AddAttachmentProfilePictureToUsers < ActiveRecord::Migration + def self.up + change_table :users do |t| + t.attachment :profile_picture + end + end + + def self.down + remove_attachment :users, :profile_picture + end +end diff --git a/db/schema.rb b/db/schema.rb index a939558f..43379d45 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20141228202825) do +ActiveRecord::Schema.define(version: 20141229085904) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -133,12 +133,12 @@ ActiveRecord::Schema.define(version: 20141228202825) do add_index "smiles", ["user_id"], name: "index_smiles_on_user_id", using: :btree create_table "users", force: true do |t| - t.string "email", default: "", null: false - t.string "encrypted_password", default: "", null: false + t.string "email", default: "", null: false + t.string "encrypted_password", default: "", null: false t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" - t.integer "sign_in_count", default: 0, null: false + t.integer "sign_in_count", default: 0, null: false t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" t.string "current_sign_in_ip" @@ -146,19 +146,23 @@ ActiveRecord::Schema.define(version: 20141228202825) do t.datetime "created_at" t.datetime "updated_at" t.string "screen_name" - t.integer "friend_count", default: 0, null: false - t.integer "follower_count", default: 0, null: false - t.integer "asked_count", default: 0, null: false - t.integer "answered_count", default: 0, null: false - t.integer "commented_count", default: 0, null: false + t.integer "friend_count", default: 0, null: false + t.integer "follower_count", default: 0, null: false + t.integer "asked_count", default: 0, null: false + t.integer "answered_count", default: 0, null: false + t.integer "commented_count", default: 0, null: false t.string "display_name" - t.integer "smiled_count", default: 0, null: false - t.boolean "admin", default: false, null: false - t.string "motivation_header", default: "", null: false - t.string "website", default: "", null: false - t.string "location", default: "", null: false - t.text "bio", default: "", null: false - t.boolean "moderator", default: false, null: false + t.integer "smiled_count", default: 0, null: false + t.boolean "admin", default: false, null: false + t.string "motivation_header", default: "", null: false + t.string "website", default: "", null: false + t.string "location", default: "", null: false + t.text "bio", default: "", null: false + t.boolean "moderator", default: false, null: false + t.string "profile_picture_file_name" + t.string "profile_picture_content_type" + t.integer "profile_picture_file_size" + t.datetime "profile_picture_updated_at" end add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree From 501f039e7fd1f237b6e618ede2a6820669630310 Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 10:18:38 +0100 Subject: [PATCH 05/25] gravatar_url returns the users' profile_picture --- app/helpers/application_helper.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index cf7e294a..3f3bfeb3 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -60,6 +60,7 @@ module ApplicationHelper end def gravatar_url(user) + return user.profile_picture.url # return '/cage.png' return '//www.gravatar.com/avatar' if user.nil? return "//www.gravatar.com/avatar/#{Digest::MD5.hexdigest(user)}" if user.is_a? String From 678e03deedae4b481ddf96a2e5bd1ba5f8a4331b Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 11:21:43 +0100 Subject: [PATCH 06/25] uploading profile pictures works now --- app/controllers/user_controller.rb | 9 +++++---- app/views/user/edit.html.haml | 4 +++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index cc560d54..3cb5eee1 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -1,4 +1,6 @@ class UserController < ApplicationController + before_filter :authenticate_user!, only: %w(edit update) + def show @user = User.where('LOWER(screen_name) = ?', params[:username].downcase).first! @answers = @user.answers.reverse_order.paginate(page: params[:page]) @@ -9,14 +11,13 @@ class UserController < ApplicationController end def edit - authenticate_user! end def update - authenticate_user! - user_attributes = params.require(:user).permit(:display_name, :motivation_header, :website, :location, :bio) + user_attributes = params.require(:user).permit(:display_name, :profile_picture, :motivation_header, :website, + :location, :bio) unless current_user.update_attributes(user_attributes) - flash[:error] = 'fork it' + flash[:error] = 'An error occurred. ;_;' end redirect_to edit_user_profile_path end diff --git a/app/views/user/edit.html.haml b/app/views/user/edit.html.haml index a39e380f..b9ffbbc0 100644 --- a/app/views/user/edit.html.haml +++ b/app/views/user/edit.html.haml @@ -4,10 +4,12 @@ = render 'layouts/messages' .panel.panel-default .panel-body - = bootstrap_form_for(current_user, url: {action: "edit"}, method: "patch") do |f| + = bootstrap_form_for(current_user, url: {action: "edit"}, :html => { :multipart => true }, method: "patch") do |f| = f.text_field :display_name, label: "Your name" + = f.file_field :profile_picture + = f.text_field :motivation_header, label: "Motivation header", placeholder: 'Ask me anything!' = f.text_field :website, label: "Website", placeholder: 'http://bad-dragon.com' From b378a03afa25c83464006a43557f4e3d08ceefd4 Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 11:58:01 +0100 Subject: [PATCH 07/25] added delayed_paperclip --- Gemfile | 1 + Gemfile.lock | 3 +++ app/models/user.rb | 4 +++- config/sidekiq.yml | 3 ++- ...20141229105013_add_profile_picture_processing_to_users.rb | 5 +++++ db/schema.rb | 3 ++- 6 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20141229105013_add_profile_picture_processing_to_users.rb diff --git a/Gemfile b/Gemfile index ed6e04f4..687613ba 100644 --- a/Gemfile +++ b/Gemfile @@ -31,6 +31,7 @@ gem 'font-awesome-rails', '~> 4.2.0.0' gem 'rails-assets-growl' gem 'jcrop-rails-v2' gem "paperclip", "~> 4.2" +gem 'delayed_paperclip' gem 'ruby-progressbar' diff --git a/Gemfile.lock b/Gemfile.lock index e33fc483..abfafd98 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -84,6 +84,8 @@ GEM crass (1.0.1) daemons (1.1.9) database_cleaner (1.3.0) + delayed_paperclip (2.9.0) + paperclip (>= 3.3) devise (3.4.1) bcrypt (~> 3.0) orm_adapter (~> 0.1) @@ -349,6 +351,7 @@ DEPENDENCIES capybara coffee-rails (~> 4.1.0) database_cleaner + delayed_paperclip devise factory_girl_rails faker diff --git a/app/models/user.rb b/app/models/user.rb index b79c6d52..66c75441 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -40,8 +40,10 @@ class User < ActiveRecord::Base # validates :website, format: { with: WEBSITE_REGEX } - has_attached_file :profile_picture, styles: { medium: "256x256>", thumb: "80x80>" }, default_url: "/images/:style/no_avatar.png" + has_attached_file :profile_picture, styles: { medium: "256x256>", thumb: "80x80>" }, + default_url: "/images/:style/no_avatar.png", use_timestamp: false validates_attachment_content_type :profile_picture, :content_type => /\Aimage\/.*\Z/ + process_in_background :profile_picture before_save do self.display_name = 'WRYYYYYYYY' if display_name == 'Dio Brando' diff --git a/config/sidekiq.yml b/config/sidekiq.yml index 6762520e..525b6171 100644 --- a/config/sidekiq.yml +++ b/config/sidekiq.yml @@ -6,4 +6,5 @@ staging: production: :concurrency: 25 :queues: - - share \ No newline at end of file + - share + - paperclip \ No newline at end of file diff --git a/db/migrate/20141229105013_add_profile_picture_processing_to_users.rb b/db/migrate/20141229105013_add_profile_picture_processing_to_users.rb new file mode 100644 index 00000000..a5f7e85d --- /dev/null +++ b/db/migrate/20141229105013_add_profile_picture_processing_to_users.rb @@ -0,0 +1,5 @@ +class AddProfilePictureProcessingToUsers < ActiveRecord::Migration + def change + add_column :users, :profile_picture_processing, :boolean + end +end diff --git a/db/schema.rb b/db/schema.rb index 43379d45..f4a65519 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20141229085904) do +ActiveRecord::Schema.define(version: 20141229105013) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -163,6 +163,7 @@ ActiveRecord::Schema.define(version: 20141229085904) do t.string "profile_picture_content_type" t.integer "profile_picture_file_size" t.datetime "profile_picture_updated_at" + t.boolean "profile_picture_processing" end add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree From 7074a1edf796d9cc04f20def2135c508a8c6008b Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 12:56:41 +0100 Subject: [PATCH 08/25] mark gravatar-url as deprecated --- app/helpers/application_helper.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 3f3bfeb3..a6d96f77 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -59,12 +59,13 @@ module ApplicationHelper ((!current_user.nil?) && ((current_user == user) || current_user.mod?)) ? true : false end + # @deprecated Use {User#profile_picture.url} instead. def gravatar_url(user) return user.profile_picture.url # return '/cage.png' - return '//www.gravatar.com/avatar' if user.nil? - return "//www.gravatar.com/avatar/#{Digest::MD5.hexdigest(user)}" if user.is_a? String - "//www.gravatar.com/avatar/#{Digest::MD5.hexdigest(user.email)}" + #return '//www.gravatar.com/avatar' if user.nil? + #return "//www.gravatar.com/avatar/#{Digest::MD5.hexdigest(user)}" if user.is_a? String + #"//www.gravatar.com/avatar/#{Digest::MD5.hexdigest(user.email)}" end def ios_web_app? From 5071e3ffe864a5fbd2c0e02908c1799f0f028fb6 Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 13:52:19 +0100 Subject: [PATCH 09/25] added JCrop to view --- app/assets/javascripts/settings.coffee | 49 +++++++++++++++++++++++++- app/views/user/edit.html.haml | 11 +++++- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/settings.coffee b/app/assets/javascripts/settings.coffee index 4f6517bb..68b8fc64 100644 --- a/app/assets/javascripts/settings.coffee +++ b/app/assets/javascripts/settings.coffee @@ -2,4 +2,51 @@ ($ document).on "submit", "form#edit_user", (evt) -> if ($ "input#user_current_password").val().length == 0 evt.preventDefault() - $("button[data-target=#modal-passwd]").trigger 'click' \ No newline at end of file + $("button[data-target=#modal-passwd]").trigger 'click' + + +# Profile pic +($ document).on 'change', 'input#user_profile_picture[type=file]', -> + input = ($ this)[0] + + ($ '#profile-picture-crop-controls').slideUp() + + if input.files and input.files[0] + fr = new FileReader() + ($ fr).on 'load', (e) -> + cropper = ($ '#profile-picture-cropper') + preview = ($ '#profile-picture-preview') + ($ '.jcrop-holder').remove() + jcrop = $.Jcrop('#profile-picture-cropper') + + preview.on 'load', -> + jcrop.setImage e.target.result, -> + side = if preview[0].naturalWidth > preview[0].naturalHeight + preview[0].naturalHeight + else + preview[0].naturalWidth + console.log side + + jcrop.setOptions + onChange: showPreview + onSelect: showPreview + aspectRatio: 1 + setSelect: [ 0, 0, side, side ] + allowSelect: false + + ($ '#profile-picture-crop-controls').slideDown() + + preview.fadeOut 400, -> + ($ this).attr('src', e.target.result) + ($ this).fadeIn 400 + + showPreview = (coords) -> + rx = 100 / coords.w + ry = 100 / coords.h + ($ '#profile-picture-preview').css + width: Math.round(rx * preview[0].naturalWidth) + 'px' + height: Math.round(ry * preview[0].naturalHeight) + 'px' + marginLeft: '-' + Math.round(rx * coords.x) + 'px' + marginTop: '-' + Math.round(ry * coords.y) + 'px' + + fr.readAsDataURL(input.files[0]) \ No newline at end of file diff --git a/app/views/user/edit.html.haml b/app/views/user/edit.html.haml index b9ffbbc0..d197767d 100644 --- a/app/views/user/edit.html.haml +++ b/app/views/user/edit.html.haml @@ -8,7 +8,16 @@ = f.text_field :display_name, label: "Your name" - = f.file_field :profile_picture + .media + .pull-left + %div.img-rounded.profile--img{style: 'width:100px;height:100px;overflow:hidden;margin-left:5px:'} + %img#profile-picture-preview{src: current_user.profile_picture.url, style: 'width: 100%; height: 100%'} + .media-body + = f.file_field :profile_picture + + .well#profile-picture-crop-controls{style: 'display: none;'} + %strong Adjust image + %img#profile-picture-cropper{src: current_user.profile_picture.url} = f.text_field :motivation_header, label: "Motivation header", placeholder: 'Ask me anything!' From bba9fb8354dca91e2bb9cffae7be6e434221d080 Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 13:56:23 +0100 Subject: [PATCH 10/25] removed gravatar warning --- app/views/user/_account.html.haml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/views/user/_account.html.haml b/app/views/user/_account.html.haml index e7f0f04d..be98fc87 100644 --- a/app/views/user/_account.html.haml +++ b/app/views/user/_account.html.haml @@ -1,11 +1,6 @@ .container.j2-page = render 'user/settings_tabs' .col-md-9.col-xs-12.col-sm-9 - .alert.alert-info - We currently only support avatars using - = succeed ',' do - %a{href: "https://en.gravatar.com"} Gravatar - after you set yours up, use the E-Mail you are using for it on here as well, we will directly use this image then! = render 'layouts/messages' .panel.panel-default .panel-body From b8d1ca5d972e3211a81dfae70bdd426ac716fdfa Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 14:45:49 +0100 Subject: [PATCH 11/25] update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 196d3a76..3f798c97 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ coverage/ .idea/ /public/assets +/public/system # damn vim backup files *~ From ba642fc36e47bb84d03bafaed66fe8755e157f67 Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 14:49:05 +0100 Subject: [PATCH 12/25] added large avatar placeholder --- public/images/large/no_avatar.png | Bin 0 -> 20734 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/images/large/no_avatar.png diff --git a/public/images/large/no_avatar.png b/public/images/large/no_avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..709109faa0c33bf78893cc5c3ef17c142121aa27 GIT binary patch literal 20734 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%0AlLsiu3OawOfcoJ%)hBGb>pIwo^wm6{~mF9KEh; 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 Date: Mon, 29 Dec 2014 14:49:26 +0100 Subject: [PATCH 13/25] renamed thumb to small --- public/images/{thumb => small}/no_avatar.png | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename public/images/{thumb => small}/no_avatar.png (100%) diff --git a/public/images/thumb/no_avatar.png b/public/images/small/no_avatar.png similarity index 100% rename from public/images/thumb/no_avatar.png rename to public/images/small/no_avatar.png From 4adc6eec0965cb04cb38eaf38f6760548d5a6467 Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 14:49:57 +0100 Subject: [PATCH 14/25] ugh --- app/assets/javascripts/settings.coffee | 6 +++++- db/migrate/20141229133149_add_crop_values_to_users.rb | 10 ++++++++++ db/schema.rb | 6 +++++- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20141229133149_add_crop_values_to_users.rb diff --git a/app/assets/javascripts/settings.coffee b/app/assets/javascripts/settings.coffee index 68b8fc64..a48f33e0 100644 --- a/app/assets/javascripts/settings.coffee +++ b/app/assets/javascripts/settings.coffee @@ -48,5 +48,9 @@ height: Math.round(ry * preview[0].naturalHeight) + 'px' marginLeft: '-' + Math.round(rx * coords.x) + 'px' marginTop: '-' + Math.round(ry * coords.y) + 'px' + ($ '#crop_x').val Math.floor(coords.x) + ($ '#crop_y').val Math.floor(coords.y) + ($ '#crop_w').val Math.floor(coords.w) + ($ '#crop_h').val Math.floor(coords.h) - fr.readAsDataURL(input.files[0]) \ No newline at end of file + fr.readAsDataURL(input.files[0]) \ No newline at end of file diff --git a/db/migrate/20141229133149_add_crop_values_to_users.rb b/db/migrate/20141229133149_add_crop_values_to_users.rb new file mode 100644 index 00000000..f3580dcf --- /dev/null +++ b/db/migrate/20141229133149_add_crop_values_to_users.rb @@ -0,0 +1,10 @@ +class AddCropValuesToUsers < ActiveRecord::Migration + def change + # this is a ugly hack and will stay until I find a way to pass parameters + # to the paperclip Sidekiq worker. oh well. + add_column :users, :crop_x, :integer + add_column :users, :crop_y, :integer + add_column :users, :crop_w, :integer + add_column :users, :crop_h, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index f4a65519..a5bcd502 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20141229105013) do +ActiveRecord::Schema.define(version: 20141229133149) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -164,6 +164,10 @@ ActiveRecord::Schema.define(version: 20141229105013) do t.integer "profile_picture_file_size" t.datetime "profile_picture_updated_at" t.boolean "profile_picture_processing" + t.integer "crop_x" + t.integer "crop_y" + t.integer "crop_w" + t.integer "crop_h" end add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree From b61a631f15500dc037d057f4d9a8d9463bee4dbb Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 14:50:25 +0100 Subject: [PATCH 15/25] added hidden fields --- app/views/user/edit.html.haml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/views/user/edit.html.haml b/app/views/user/edit.html.haml index d197767d..be7ebd6d 100644 --- a/app/views/user/edit.html.haml +++ b/app/views/user/edit.html.haml @@ -27,4 +27,7 @@ = f.text_area :bio, label: "Bio", placeholder: 'In Bio war ich nie gut x--DD' + - for attrib in %i(crop_x crop_y crop_w crop_h) + = f.hidden_field attrib, id: attrib + = f.submit "Save settings", class: 'btn btn-primary' \ No newline at end of file From 7aa954e21213cfafd9930b786cdcfb7b04c00ede Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 14:51:52 +0100 Subject: [PATCH 16/25] added cropper processor --- app/models/user.rb | 9 +++++++-- lib/paperclip_processors/cropper.rb | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 lib/paperclip_processors/cropper.rb diff --git a/app/models/user.rb b/app/models/user.rb index 66c75441..05048789 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -40,8 +40,9 @@ class User < ActiveRecord::Base # validates :website, format: { with: WEBSITE_REGEX } - has_attached_file :profile_picture, styles: { medium: "256x256>", thumb: "80x80>" }, - default_url: "/images/:style/no_avatar.png", use_timestamp: false + has_attached_file :profile_picture, styles: { large: "500x500#", medium: "256x256#", small: "80x80#" }, + default_url: "/images/:style/no_avatar.png", use_timestamp: false, + processors: [:cropper] validates_attachment_content_type :profile_picture, :content_type => /\Aimage\/.*\Z/ process_in_background :profile_picture @@ -155,4 +156,8 @@ class User < ActiveRecord::Base def report_comment(report, content) ModerationComment.create!(user: self, report: report, content: content) end + + def cropping? + !crop_x.blank? && !crop_y.blank? && !crop_w.blank? && !crop_h.blank? + end end diff --git a/lib/paperclip_processors/cropper.rb b/lib/paperclip_processors/cropper.rb new file mode 100644 index 00000000..29cf6771 --- /dev/null +++ b/lib/paperclip_processors/cropper.rb @@ -0,0 +1,22 @@ +module Paperclip + class Cropper < Thumbnail + def transformation_command + if crop_command + x = super + i = x.index '-crop' + 2.times { x.delete_at i } if i + x + else + super + end + end + + def crop_command + target = @attachment.instance + if target.cropping? + ['-crop', "'#{target.crop_w.to_i}x#{target.crop_h.to_i}+#{target.crop_x.to_i}+#{target.crop_y.to_i}'"] + end + end + end +end + From 3e033cc1025fa327ef70a831ec8f4768072fa54d Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 14:52:06 +0100 Subject: [PATCH 17/25] permit more params! --- app/controllers/user_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index 3cb5eee1..ffad7d8f 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -15,7 +15,7 @@ class UserController < ApplicationController def update user_attributes = params.require(:user).permit(:display_name, :profile_picture, :motivation_header, :website, - :location, :bio) + :location, :bio, :crop_x, :crop_y, :crop_w, :crop_h) unless current_user.update_attributes(user_attributes) flash[:error] = 'An error occurred. ;_;' end From e7a0d77fd4f43ebab55a9040a8ae5c4290370e62 Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 14:54:32 +0100 Subject: [PATCH 18/25] changed flash thing --- app/controllers/user_controller.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index ffad7d8f..8124e1e8 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -16,7 +16,11 @@ class UserController < ApplicationController def update user_attributes = params.require(:user).permit(:display_name, :profile_picture, :motivation_header, :website, :location, :bio, :crop_x, :crop_y, :crop_w, :crop_h) - unless current_user.update_attributes(user_attributes) + if current_user.update_attributes(user_attributes) + text = 'Your profile has been updated!' + text += ' It might take a few minutes until your new profile picture is shown everywhere.' if user_attributes[:profile_picture] + flash[:success] = text + else flash[:error] = 'An error occurred. ;_;' end redirect_to edit_user_profile_path From f7cb3478bec21da7239f215fc926ebaadc02cf21 Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 14:57:16 +0100 Subject: [PATCH 19/25] :medium everywhere --- app/helpers/application_helper.rb | 2 +- app/views/user/edit.html.haml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index a6d96f77..5873f7db 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -61,7 +61,7 @@ module ApplicationHelper # @deprecated Use {User#profile_picture.url} instead. def gravatar_url(user) - return user.profile_picture.url + return user.profile_picture.url :medium # return '/cage.png' #return '//www.gravatar.com/avatar' if user.nil? #return "//www.gravatar.com/avatar/#{Digest::MD5.hexdigest(user)}" if user.is_a? String diff --git a/app/views/user/edit.html.haml b/app/views/user/edit.html.haml index be7ebd6d..fe057bd5 100644 --- a/app/views/user/edit.html.haml +++ b/app/views/user/edit.html.haml @@ -11,13 +11,13 @@ .media .pull-left %div.img-rounded.profile--img{style: 'width:100px;height:100px;overflow:hidden;margin-left:5px:'} - %img#profile-picture-preview{src: current_user.profile_picture.url, style: 'width: 100%; height: 100%'} + %img#profile-picture-preview{src: current_user.profile_picture.url(:medium), style: 'width: 100%; height: 100%'} .media-body = f.file_field :profile_picture .well#profile-picture-crop-controls{style: 'display: none;'} %strong Adjust image - %img#profile-picture-cropper{src: current_user.profile_picture.url} + %img#profile-picture-cropper{src: current_user.profile_picture.url(:medium)} = f.text_field :motivation_header, label: "Motivation header", placeholder: 'Ask me anything!' From baba0335ce61a8c5d748b6c3d1e44dba12a2ae4c Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 14:59:12 +0100 Subject: [PATCH 20/25] oh fuck --- lib/paperclip_processors/cropper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/paperclip_processors/cropper.rb b/lib/paperclip_processors/cropper.rb index 29cf6771..f2677029 100644 --- a/lib/paperclip_processors/cropper.rb +++ b/lib/paperclip_processors/cropper.rb @@ -5,7 +5,7 @@ module Paperclip x = super i = x.index '-crop' 2.times { x.delete_at i } if i - x + crop_command + x else super end From b2c6d893e3f9ab9b5d97a7eef4c7713da6608d28 Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 15:45:07 +0100 Subject: [PATCH 21/25] FUCK Jcrop! --- Gemfile | 1 - Gemfile.lock | 2 -- 2 files changed, 3 deletions(-) diff --git a/Gemfile b/Gemfile index 687613ba..e281b595 100644 --- a/Gemfile +++ b/Gemfile @@ -29,7 +29,6 @@ gem 'font-kit-rails' gem 'nprogress-rails' gem 'font-awesome-rails', '~> 4.2.0.0' gem 'rails-assets-growl' -gem 'jcrop-rails-v2' gem "paperclip", "~> 4.2" gem 'delayed_paperclip' diff --git a/Gemfile.lock b/Gemfile.lock index abfafd98..f26a58a5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -129,7 +129,6 @@ GEM jbuilder (2.2.5) activesupport (>= 3.0.0, < 5) multi_json (~> 1.2) - jcrop-rails-v2 (0.9.12.3) jquery-rails (3.1.2) railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) @@ -361,7 +360,6 @@ DEPENDENCIES haml http_accept_language jbuilder (~> 2.2.4) - jcrop-rails-v2 jquery-rails jquery-turbolinks mysql2 From 26363c4742b9a7c6d1349e20638e2f45ab139b78 Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 15:47:10 +0100 Subject: [PATCH 22/25] added jquery.guillotine --- .../javascripts/application.js.erb.coffee | 2 +- app/assets/stylesheets/application.css.scss | 2 +- lib/assets/javascripts/jquery.guillotine.js | 417 ++++++++++++++++++ lib/assets/stylesheets/jquery.guillotine.css | 28 ++ 4 files changed, 447 insertions(+), 2 deletions(-) create mode 100644 lib/assets/javascripts/jquery.guillotine.js create mode 100644 lib/assets/stylesheets/jquery.guillotine.css diff --git a/app/assets/javascripts/application.js.erb.coffee b/app/assets/javascripts/application.js.erb.coffee index fda6f467..ef98ffe4 100644 --- a/app/assets/javascripts/application.js.erb.coffee +++ b/app/assets/javascripts/application.js.erb.coffee @@ -7,7 +7,7 @@ #= require nprogress-turbolinks #= require growl #= require cheet -#= require jquery.Jcrop +#= require jquery.guillotine #= require_tree . NProgress.configure diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss index 5c522e6b..e88e57cc 100644 --- a/app/assets/stylesheets/application.css.scss +++ b/app/assets/stylesheets/application.css.scss @@ -1,7 +1,7 @@ /* *= require rails_bootstrap_forms *= require growl - *= require jquery.Jcrop + *= require jquery.guillotine *= require_self */ diff --git a/lib/assets/javascripts/jquery.guillotine.js b/lib/assets/javascripts/jquery.guillotine.js new file mode 100644 index 00000000..3d6cb0b1 --- /dev/null +++ b/lib/assets/javascripts/jquery.guillotine.js @@ -0,0 +1,417 @@ +// Generated by CoffeeScript 1.8.0 + +/* + * jQuery Guillotine Plugin v1.3.0 + * http://matiasgagliano.github.com/guillotine/ + * + * Copyright 2014, Matías Gagliano. + * Dual licensed under the MIT or GPLv3 licenses. + * http://opensource.org/licenses/MIT + * http://opensource.org/licenses/GPL-3.0 + * + */ + +(function() { + "use strict"; + var $, Guillotine, canTransform, defaults, events, getPointerPosition, hardwareAccelerate, isTouch, pluginName, scope, touchRegExp, validEvent, whitelist, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + $ = jQuery; + + pluginName = 'guillotine'; + + scope = 'guillotine'; + + events = { + start: "touchstart." + scope + " mousedown." + scope + " pointerdown." + scope, + move: "touchmove." + scope + " mousemove." + scope + " pointermove." + scope, + stop: "touchend." + scope + " mouseup." + scope + " pointerup." + scope + }; + + defaults = { + width: 400, + height: 300, + zoomStep: 0.1, + init: null, + eventOnChange: null, + onChange: null + }; + + touchRegExp = /touch/i; + + isTouch = function(e) { + return touchRegExp.test(e.type); + }; + + validEvent = function(e) { + if (isTouch(e)) { + return e.originalEvent.changedTouches.length === 1; + } else { + return e.which === 1; + } + }; + + getPointerPosition = function(e) { + if (isTouch(e)) { + e = e.originalEvent.touches[0]; + } + return { + x: e.pageX, + y: e.pageY + }; + }; + + canTransform = function() { + var hasTransform, helper, prefix, prefixes, prop, test, tests, value, _i, _len; + hasTransform = false; + prefixes = 'webkit,Moz,O,ms,Khtml'.split(','); + tests = { + transform: 'transform' + }; + for (_i = 0, _len = prefixes.length; _i < _len; _i++) { + prefix = prefixes[_i]; + tests[prefix + 'Transform'] = "-" + (prefix.toLowerCase()) + "-transform"; + } + helper = document.createElement('img'); + document.body.insertBefore(helper, null); + for (test in tests) { + prop = tests[test]; + if (helper.style[test] === void 0) { + continue; + } + helper.style[test] = 'rotate(90deg)'; + value = window.getComputedStyle(helper).getPropertyValue(prop); + if ((value != null) && value.length && value !== 'none') { + hasTransform = true; + break; + } + } + document.body.removeChild(helper); + canTransform = hasTransform ? (function() { + return true; + }) : (function() { + return false; + }); + return canTransform(); + }; + + hardwareAccelerate = function(el) { + return $(el).css({ + '-webkit-perspective': 1000, + 'perspective': 1000, + '-webkit-backface-visibility': 'hidden', + 'backface-visibility': 'hidden' + }); + }; + + Guillotine = (function() { + function Guillotine(element, options) { + this._drag = __bind(this._drag, this); + this._unbind = __bind(this._unbind, this); + this._start = __bind(this._start, this); + var _ref; + this.op = $.extend(true, {}, defaults, options, $(element).data(pluginName)); + this.enabled = true; + this.zoomInFactor = 1 + this.op.zoomStep; + this.zoomOutFactor = 1 / this.zoomInFactor; + _ref = [0, 0, 0, 0, 0], this.width = _ref[0], this.height = _ref[1], this.left = _ref[2], this.top = _ref[3], this.angle = _ref[4]; + this.data = { + scale: 1, + angle: 0, + x: 0, + y: 0, + w: this.op.width, + h: this.op.height + }; + this._wrap(element); + if (this.op.init != null) { + this._init(); + } + if (this.width < 1 || this.height < 1) { + this._fit() && this._center(); + } + hardwareAccelerate(this.$el); + this.$el.on(events.start, this._start); + } + + Guillotine.prototype._wrap = function(element) { + var canvas, el, guillotine, height, img, paddingTop, width, _ref, _ref1, _ref2; + el = $(element); + if (el.prop('tagName') === 'IMG') { + img = document.createElement('img'); + img.src = el.attr('src'); + _ref = [img.width, img.height], width = _ref[0], height = _ref[1]; + } else { + _ref1 = [el.width(), el.height()], width = _ref1[0], height = _ref1[1]; + } + _ref2 = [width / this.op.width, height / this.op.height], this.width = _ref2[0], this.height = _ref2[1]; + canvas = $('

').addClass('guillotine-canvas'); + canvas.css({ + width: this.width * 100 + '%', + height: this.height * 100 + '%', + top: 0, + left: 0 + }); + canvas = el.wrap(canvas).parent(); + paddingTop = this.op.height / this.op.width * 100 + '%'; + guillotine = $('
').addClass('guillotine-window'); + guillotine.css({ + width: '100%', + height: 'auto', + 'padding-top': paddingTop + }); + guillotine = canvas.wrap(guillotine).parent(); + this.$el = el; + this.el = el[0]; + this.$canvas = canvas; + this.canvas = canvas[0]; + this.$gllt = guillotine; + this.gllt = guillotine[0]; + return this.$document = $(element.ownerDocument); + }; + + Guillotine.prototype._unwrap = function() { + this.$el.removeAttr('style'); + this.$el.insertBefore(this.gllt); + return this.$gllt.remove(); + }; + + Guillotine.prototype._init = function() { + var angle, o, scale; + o = this.op.init; + if ((scale = parseFloat(o.scale))) { + this._zoom(scale); + } + if ((angle = parseInt(o.angle))) { + this._rotate(angle); + } + return this._offset(parseInt(o.x) / this.op.width || 0, parseInt(o.y) / this.op.height || 0); + }; + + Guillotine.prototype._start = function(e) { + if (!(this.enabled && validEvent(e))) { + return; + } + e.preventDefault(); + e.stopImmediatePropagation(); + this.p = getPointerPosition(e); + return this._bind(); + }; + + Guillotine.prototype._bind = function() { + this.$document.on(events.move, this._drag); + return this.$document.on(events.stop, this._unbind); + }; + + Guillotine.prototype._unbind = function(e) { + this.$document.off(events.move, this._drag); + this.$document.off(events.stop, this._unbind); + if (e != null) { + return this._trigger('drag'); + } + }; + + Guillotine.prototype._trigger = function(action) { + if (this.op.eventOnChange != null) { + this.$el.trigger(this.op.eventOnChange, [this.data, action]); + } + if (typeof this.op.onChange === 'function') { + return this.op.onChange.call(this.el, this.data, action); + } + }; + + Guillotine.prototype._drag = function(e) { + var dx, dy, left, p, top; + e.preventDefault(); + e.stopImmediatePropagation(); + p = getPointerPosition(e); + dx = p.x - this.p.x; + dy = p.y - this.p.y; + this.p = p; + left = dx === 0 ? null : this.left - dx / this.gllt.clientWidth; + top = dy === 0 ? null : this.top - dy / this.gllt.clientHeight; + return this._offset(left, top); + }; + + Guillotine.prototype._offset = function(left, top) { + if (left || left === 0) { + if (left < 0) { + left = 0; + } + if (left > this.width - 1) { + left = this.width - 1; + } + this.canvas.style.left = (-left * 100).toFixed(2) + '%'; + this.left = left; + this.data.x = Math.round(left * this.op.width); + } + if (top || top === 0) { + if (top < 0) { + top = 0; + } + if (top > this.height - 1) { + top = this.height - 1; + } + this.canvas.style.top = (-top * 100).toFixed(2) + '%'; + this.top = top; + return this.data.y = Math.round(top * this.op.height); + } + }; + + Guillotine.prototype._zoom = function(factor) { + var h, left, top, w, _ref; + if (factor <= 0 || factor === 1) { + return; + } + _ref = [this.width, this.height], w = _ref[0], h = _ref[1]; + if (w * factor > 1 && h * factor > 1) { + this.width *= factor; + this.height *= factor; + this.canvas.style.width = (this.width * 100).toFixed(2) + '%'; + this.canvas.style.height = (this.height * 100).toFixed(2) + '%'; + this.data.scale *= factor; + } else { + this._fit(); + factor = this.width / w; + } + left = (this.left + 0.5) * factor - 0.5; + top = (this.top + 0.5) * factor - 0.5; + return this._offset(left, top); + }; + + Guillotine.prototype._fit = function() { + var prevWidth, relativeRatio; + prevWidth = this.width; + relativeRatio = this.height / this.width; + if (relativeRatio > 1) { + this.width = 1; + this.height = relativeRatio; + } else { + this.width = 1 / relativeRatio; + this.height = 1; + } + this.canvas.style.width = (this.width * 100).toFixed(2) + '%'; + this.canvas.style.height = (this.height * 100).toFixed(2) + '%'; + return this.data.scale *= this.width / prevWidth; + }; + + Guillotine.prototype._center = function() { + return this._offset((this.width - 1) / 2, (this.height - 1) / 2); + }; + + Guillotine.prototype._rotate = function(angle) { + var canvasRatio, glltRatio, h, w, _ref, _ref1, _ref2; + if (!canTransform()) { + return; + } + if (!(angle !== 0 && angle % 90 === 0)) { + return; + } + this.angle = (this.angle + angle) % 360; + if (this.angle < 0) { + this.angle = 360 + this.angle; + } + if (angle % 180 !== 0) { + glltRatio = this.op.height / this.op.width; + _ref = [this.height * glltRatio, this.width / glltRatio], this.width = _ref[0], this.height = _ref[1]; + if (this.width >= 1 && this.height >= 1) { + this.canvas.style.width = this.width * 100 + '%'; + this.canvas.style.height = this.height * 100 + '%'; + } else { + this._fit(); + } + } + _ref1 = [1, 1], w = _ref1[0], h = _ref1[1]; + if (this.angle % 180 !== 0) { + canvasRatio = this.height / this.width * glltRatio; + _ref2 = [canvasRatio, 1 / canvasRatio], w = _ref2[0], h = _ref2[1]; + } + this.el.style.width = w * 100 + '%'; + this.el.style.height = h * 100 + '%'; + this.el.style.left = (1 - w) / 2 * 100 + '%'; + this.el.style.top = (1 - h) / 2 * 100 + '%'; + this.$el.css({ + transform: "rotate(" + this.angle + "deg)" + }); + this._center(); + return this.data.angle = this.angle; + }; + + Guillotine.prototype.rotateLeft = function() { + return this.enabled && (this._rotate(-90), this._trigger('rotateLeft')); + }; + + Guillotine.prototype.rotateRight = function() { + return this.enabled && (this._rotate(90), this._trigger('rotateRight')); + }; + + Guillotine.prototype.center = function() { + return this.enabled && (this._center(), this._trigger('center')); + }; + + Guillotine.prototype.fit = function() { + return this.enabled && (this._fit(), this._center(), this._trigger('fit')); + }; + + Guillotine.prototype.zoomIn = function() { + return this.enabled && (this._zoom(this.zoomInFactor), this._trigger('zoomIn')); + }; + + Guillotine.prototype.zoomOut = function() { + return this.enabled && (this._zoom(this.zoomOutFactor), this._trigger('zoomOut')); + }; + + Guillotine.prototype.getData = function() { + return this.data; + }; + + Guillotine.prototype.enable = function() { + return this.enabled = true; + }; + + Guillotine.prototype.disable = function() { + return this.enabled = false; + }; + + Guillotine.prototype.remove = function() { + this._unbind(); + this._unwrap(); + this.disable(); + this.$el.off(events.start, this._start); + return this.$el.removeData(pluginName + 'Instance'); + }; + + return Guillotine; + + })(); + + whitelist = ['rotateLeft', 'rotateRight', 'center', 'fit', 'zoomIn', 'zoomOut', 'instance', 'getData', 'enable', 'disable', 'remove']; + + $.fn[pluginName] = function(options) { + if (typeof options !== 'string') { + return this.each(function() { + var guillotine; + if (!$.data(this, pluginName + 'Instance')) { + guillotine = new Guillotine(this, options); + return $.data(this, pluginName + 'Instance', guillotine); + } + }); + } else if (__indexOf.call(whitelist, options) >= 0) { + if (options === 'instance') { + return $.data(this[0], pluginName + 'Instance'); + } + if (options === 'getData') { + return $.data(this[0], pluginName + 'Instance')[options](); + } + return this.each(function() { + var guillotine; + guillotine = $.data(this, pluginName + 'Instance'); + if (guillotine) { + return guillotine[options](); + } + }); + } + }; + +}).call(this); diff --git a/lib/assets/stylesheets/jquery.guillotine.css b/lib/assets/stylesheets/jquery.guillotine.css new file mode 100644 index 00000000..62df7e9b --- /dev/null +++ b/lib/assets/stylesheets/jquery.guillotine.css @@ -0,0 +1,28 @@ +.guillotine-window { + display: block; + position: relative; + overflow: hidden; +} + +.guillotine-canvas { + position: absolute; + top: 0; + left: 0; + text-align: center; + margin: 0 !important; + padding: 0 !important; + border: none !important; +} + +.guillotine-canvas > * { + position: absolute; + top: 0; + left: 0; + max-width: none; + max-height: none; + width: 100%; + height: 100%; + margin: 0 !important; + padding: 0 !important; + border: none !important; +} From fa16612ba86a6a6a965c8f097aa6a0776878a5b9 Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 16:29:46 +0100 Subject: [PATCH 23/25] made the new cropper work --- app/assets/javascripts/settings.coffee | 68 ++++++++++++-------------- app/views/user/edit.html.haml | 16 ++++-- 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/app/assets/javascripts/settings.coffee b/app/assets/javascripts/settings.coffee index a48f33e0..a11947ad 100644 --- a/app/assets/javascripts/settings.coffee +++ b/app/assets/javascripts/settings.coffee @@ -9,48 +9,40 @@ ($ document).on 'change', 'input#user_profile_picture[type=file]', -> input = ($ this)[0] - ($ '#profile-picture-crop-controls').slideUp() + ($ '#profile-picture-crop-controls').slideUp 400, -> + if input.files and input.files[0] + fr = new FileReader() + ($ fr).on 'load', (e) -> + cropper = ($ '#profile-picture-cropper') + preview = ($ '#profile-picture-preview') - if input.files and input.files[0] - fr = new FileReader() - ($ fr).on 'load', (e) -> - cropper = ($ '#profile-picture-cropper') - preview = ($ '#profile-picture-preview') - ($ '.jcrop-holder').remove() - jcrop = $.Jcrop('#profile-picture-cropper') - - preview.on 'load', -> - jcrop.setImage e.target.result, -> - side = if preview[0].naturalWidth > preview[0].naturalHeight - preview[0].naturalHeight + cropper.on 'load', -> + side = if cropper[0].naturalWidth > cropper[0].naturalHeight + cropper[0].naturalHeight else - preview[0].naturalWidth - console.log side + cropper[0].naturalWidth - jcrop.setOptions - onChange: showPreview - onSelect: showPreview - aspectRatio: 1 - setSelect: [ 0, 0, side, side ] - allowSelect: false + cropper.guillotine + width: side + height: side + onChange: (data, action) -> + console.log data + ($ '#crop_x').val Math.floor(data.x) + ($ '#crop_y').val Math.floor(data.y) + ($ '#crop_w').val Math.floor(data.w) + ($ '#crop_h').val Math.floor(data.h) +# rx = 100 / data.w +# ry = 100 / data.h +# ($ '#profile-picture-preview').css +# width: Math.round(rx * preview[0].naturalWidth) + 'px' +# height: Math.round(ry * preview[0].naturalHeight) + 'px' +# marginLeft: '-' + Math.round(rx * data.x) + 'px' +# marginTop: '-' + Math.round(ry * data.y) + 'px' + ($ '#cropper-zoom-out').click -> cropper.guillotine 'zoomOut' + ($ '#cropper-zoom-in').click -> cropper.guillotine 'zoomIn' ($ '#profile-picture-crop-controls').slideDown() - preview.fadeOut 400, -> - ($ this).attr('src', e.target.result) - ($ this).fadeIn 400 + cropper.attr 'src', e.target.result - showPreview = (coords) -> - rx = 100 / coords.w - ry = 100 / coords.h - ($ '#profile-picture-preview').css - width: Math.round(rx * preview[0].naturalWidth) + 'px' - height: Math.round(ry * preview[0].naturalHeight) + 'px' - marginLeft: '-' + Math.round(rx * coords.x) + 'px' - marginTop: '-' + Math.round(ry * coords.y) + 'px' - ($ '#crop_x').val Math.floor(coords.x) - ($ '#crop_y').val Math.floor(coords.y) - ($ '#crop_w').val Math.floor(coords.w) - ($ '#crop_h').val Math.floor(coords.h) - - fr.readAsDataURL(input.files[0]) \ No newline at end of file + fr.readAsDataURL(input.files[0]) \ No newline at end of file diff --git a/app/views/user/edit.html.haml b/app/views/user/edit.html.haml index fe057bd5..bd2540c7 100644 --- a/app/views/user/edit.html.haml +++ b/app/views/user/edit.html.haml @@ -10,14 +10,20 @@ .media .pull-left - %div.img-rounded.profile--img{style: 'width:100px;height:100px;overflow:hidden;margin-left:5px:'} - %img#profile-picture-preview{src: current_user.profile_picture.url(:medium), style: 'width: 100%; height: 100%'} + %img.img-rounded.profile--img{src: current_user.profile_picture.url(:medium)} .media-body = f.file_field :profile_picture - .well#profile-picture-crop-controls{style: 'display: none;'} - %strong Adjust image - %img#profile-picture-cropper{src: current_user.profile_picture.url(:medium)} + .row#profile-picture-crop-controls{style: 'display: none;'} + .col-sm-10.col-md-8 + %strong Adjust your new image + %img#profile-picture-cropper{src: current_user.profile_picture.url(:medium)} + .col-sm-2.col-md-4 + .btn-group + %button#cropper-zoom-out.btn.btn-inverse{type: :button} + %i.fa.fa-search-minus + %button#cropper-zoom-in.btn.btn-inverse{type: :button} + %i.fa.fa-search-plus = f.text_field :motivation_header, label: "Motivation header", placeholder: 'Ask me anything!' From 338fa5bdb2721d180a69c9fa5e31bd381689a727 Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 16:39:27 +0100 Subject: [PATCH 24/25] divide by scale --- app/assets/javascripts/settings.coffee | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/assets/javascripts/settings.coffee b/app/assets/javascripts/settings.coffee index a11947ad..3d50f262 100644 --- a/app/assets/javascripts/settings.coffee +++ b/app/assets/javascripts/settings.coffee @@ -27,17 +27,17 @@ height: side onChange: (data, action) -> console.log data - ($ '#crop_x').val Math.floor(data.x) - ($ '#crop_y').val Math.floor(data.y) - ($ '#crop_w').val Math.floor(data.w) - ($ '#crop_h').val Math.floor(data.h) -# rx = 100 / data.w -# ry = 100 / data.h -# ($ '#profile-picture-preview').css -# width: Math.round(rx * preview[0].naturalWidth) + 'px' -# height: Math.round(ry * preview[0].naturalHeight) + 'px' -# marginLeft: '-' + Math.round(rx * data.x) + 'px' -# marginTop: '-' + Math.round(ry * data.y) + 'px' + ($ '#crop_x').val Math.floor(data.x / data.scale) + ($ '#crop_y').val Math.floor(data.y / data.scale) + ($ '#crop_w').val Math.floor(data.w / data.scale) + ($ '#crop_h').val Math.floor(data.h / data.scale) + # rx = 100 / data.w + # ry = 100 / data.h + # ($ '#profile-picture-preview').css + # width: Math.round(rx * preview[0].naturalWidth) + 'px' + # height: Math.round(ry * preview[0].naturalHeight) + 'px' + # marginLeft: '-' + Math.round(rx * data.x) + 'px' + # marginTop: '-' + Math.round(ry * data.y) + 'px' ($ '#cropper-zoom-out').click -> cropper.guillotine 'zoomOut' ($ '#cropper-zoom-in').click -> cropper.guillotine 'zoomIn' From 8998b8402744c094543796bcb40a2e4cc0763649 Mon Sep 17 00:00:00 2001 From: nilsding Date: Mon, 29 Dec 2014 17:22:43 +0100 Subject: [PATCH 25/25] updateVars is now called when the image finished loading --- app/assets/javascripts/settings.coffee | 29 ++++++++++++++------------ 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/settings.coffee b/app/assets/javascripts/settings.coffee index 3d50f262..5742e5b9 100644 --- a/app/assets/javascripts/settings.coffee +++ b/app/assets/javascripts/settings.coffee @@ -16,6 +16,19 @@ cropper = ($ '#profile-picture-cropper') preview = ($ '#profile-picture-preview') + updateVars = (data, action) -> + ($ '#crop_x').val Math.floor(data.x / data.scale) + ($ '#crop_y').val Math.floor(data.y / data.scale) + ($ '#crop_w').val Math.floor(data.w / data.scale) + ($ '#crop_h').val Math.floor(data.h / data.scale) +# rx = 100 / data.w +# ry = 100 / data.h +# ($ '#profile-picture-preview').css +# width: Math.round(rx * preview[0].naturalWidth) + 'px' +# height: Math.round(ry * preview[0].naturalHeight) + 'px' +# marginLeft: '-' + Math.round(rx * data.x) + 'px' +# marginTop: '-' + Math.round(ry * data.y) + 'px' + cropper.on 'load', -> side = if cropper[0].naturalWidth > cropper[0].naturalHeight cropper[0].naturalHeight @@ -25,19 +38,9 @@ cropper.guillotine width: side height: side - onChange: (data, action) -> - console.log data - ($ '#crop_x').val Math.floor(data.x / data.scale) - ($ '#crop_y').val Math.floor(data.y / data.scale) - ($ '#crop_w').val Math.floor(data.w / data.scale) - ($ '#crop_h').val Math.floor(data.h / data.scale) - # rx = 100 / data.w - # ry = 100 / data.h - # ($ '#profile-picture-preview').css - # width: Math.round(rx * preview[0].naturalWidth) + 'px' - # height: Math.round(ry * preview[0].naturalHeight) + 'px' - # marginLeft: '-' + Math.round(rx * data.x) + 'px' - # marginTop: '-' + Math.round(ry * data.y) + 'px' + onChange: updateVars + + updateVars cropper.guillotine('getData'), 'drag' # just because ($ '#cropper-zoom-out').click -> cropper.guillotine 'zoomOut' ($ '#cropper-zoom-in').click -> cropper.guillotine 'zoomIn'