From c91b2144f4bf1cae1ac217bbcb2cc66f4da3a15e Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Wed, 9 Apr 2014 14:14:02 +0300 Subject: [PATCH 01/64] sphinx search return 100 ids --- app/models/fun.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/fun.rb b/app/models/fun.rb index 3b02f19..5c6716b 100644 --- a/app/models/fun.rb +++ b/app/models/fun.rb @@ -176,7 +176,7 @@ def search_fun_ids(query, types=[]) type_index = [] unless types.nil? DEF_TYPES.each{|t| type_index << DEF_TYPES.index(t) if t.in? types } - Fun.search_for_ids(query, with: {type: type_index}, max_matches: 100, per_page: 10) + Fun.search_for_ids(query, with: {type: type_index}, max_matches: 100, per_page: 100) end end From cb6923926fcd437218ece5d0e320817923f9a6e5 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Wed, 9 Apr 2014 15:41:08 +0300 Subject: [PATCH 02/64] fix error for nil type --- app/models/fun.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/fun.rb b/app/models/fun.rb index 5c6716b..fc9821d 100644 --- a/app/models/fun.rb +++ b/app/models/fun.rb @@ -187,7 +187,7 @@ def create_tag_cloud(type) type.each do |t| tags.concat t.capitalize.constantize.tag_counts_on(:tags) end - elsif type != 'unknown' + elsif type tags = type.capitalize.constantize.tag_counts_on(:tags) end tags.uniq.shuffle From dcdb91f247362463570fccd2168289dc4052714a Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Wed, 9 Apr 2014 16:38:52 +0300 Subject: [PATCH 03/64] dry navigation --- app/views/layouts/_navigation.html.slim | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/views/layouts/_navigation.html.slim b/app/views/layouts/_navigation.html.slim index 8f682ab..016f040 100644 --- a/app/views/layouts/_navigation.html.slim +++ b/app/views/layouts/_navigation.html.slim @@ -5,10 +5,7 @@ section.nav_bar = link_to_type 'video' = link_to_type 'post' nav.menu[role="navigation"] - - if request.path == '/' - = link_to_menu "Новое", request.path, {class: 'new_funs', rel: 'tooltip', title: t('funs.titles.new')} - - else - = link_to_menu "Новое", new_path, { class: 'new_funs' , rel: 'tooltip', title: t('funs.titles.new') } + = link_to_menu "Новое", (request.path == '/' ? request.path : new_path), { class: 'new_funs' , rel: 'tooltip', title: t('funs.titles.new') } = link_to_menu "Популярное", hot_path, {class: 'popular_funs' , rel: 'tooltip', title: t('funs.titles.popular')} = link_to_menu "Обсуждаемое", discuss_path, { class: 'discussed_funs', rel: 'tooltip', title: t('funs.titles.discussed')} = link_to_menu "Песочница", sandbox_path, { class: 'sandbox_funs', rel: 'tooltip', title: t('funs.titles.sandbox')} From 196d9eb53cf8530908574810bcd59a0a8c383d10 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Thu, 10 Apr 2014 12:52:12 +0300 Subject: [PATCH 04/64] edit fun --- app/assets/javascripts/application.js | 8 +++- .../javascripts/funs/{add_fun.js => popup.js} | 17 +++----- app/assets/stylesheets/inc/_helpers.css.scss | 7 +++- app/assets/stylesheets/inc/_modals.css.scss | 40 ++++++++++++------- app/controllers/funs_controller.rb | 14 +++++-- app/views/funs/edit.html.slim | 26 ++++++------ app/views/funs/images/_edit.html.slim | 24 ++++++----- app/views/funs/posts/_edit.html.slim | 7 ++-- app/views/funs/show.html.slim | 1 + app/views/funs/videos/_edit.html.slim | 8 ++-- app/views/layouts/_header.html.slim | 2 +- config/locales/ru.yml | 1 + 12 files changed, 92 insertions(+), 63 deletions(-) rename app/assets/javascripts/funs/{add_fun.js => popup.js} (69%) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 83f030e..f7c30f1 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -140,8 +140,14 @@ $(function(){ ] }); return false - } + }; + // Initialize fancybox for add box + + $('.fancybox_ajax').not('[data-auth]').fancybox({ + type: 'ajax', + padding : 0 + }); }); function show_notice(text, type, options) { diff --git a/app/assets/javascripts/funs/add_fun.js b/app/assets/javascripts/funs/popup.js similarity index 69% rename from app/assets/javascripts/funs/add_fun.js rename to app/assets/javascripts/funs/popup.js index ecc7529..8ebd7c2 100644 --- a/app/assets/javascripts/funs/add_fun.js +++ b/app/assets/javascripts/funs/popup.js @@ -1,12 +1,5 @@ $(function(){ - // Initialize fancybox for add box - - $('.link_new_fun').not('[data-auth]').fancybox({ - type: 'ajax', - padding : 0 - }); - $(document).on('show', '.add_fun_form a[data-toggle="tab"]', function(e){ $('.add_fun_form .tab_content').find('input, textarea').attr('disabled', 'disabled'); $('.add_fun_form .tab_content ' + e.target.hash).find('input, textarea').removeAttr('disabled'); @@ -16,17 +9,17 @@ $(function(){ $('#new_fun').resetClientSideValidations(); }); - $(document).on('ajax:success', '#new_fun', function(evt, data, status, xhr){ + $(document).on('ajax:success', '#new_fun, #edit_fun', function(evt, data, status, xhr){ $.fancybox.close(); if (data.success){ - window.location.href = data.path; - } - else{ + if (data.path) window.location.href = data.path; + else window.location.reload() + }else{ show_notice(data.notice, 'error') } }); - $(document).on('ajax:beforeSend, submit', '#new_fun, #new_report', function(evt, data, status, xhr){ + $(document).on('ajax:beforeSend, submit', '#new_fun, #edit_fun, #new_report', function(){ $('.add_fun_form').append($('
')); }); diff --git a/app/assets/stylesheets/inc/_helpers.css.scss b/app/assets/stylesheets/inc/_helpers.css.scss index f85a175..e5694a3 100644 --- a/app/assets/stylesheets/inc/_helpers.css.scss +++ b/app/assets/stylesheets/inc/_helpers.css.scss @@ -7,4 +7,9 @@ .even { background: #f5f5f6; &:hover {background: #f1f1f3;} -} \ No newline at end of file +} +.text-left {text-align: left} +.text-center {text-align: center} +.text-right {text-align: right} +.vertical-space-sm {margin-top: 5px; margin-bottom: 5px;} +.vertical-space {margin-top: 10px; margin-bottom: 10px;} \ No newline at end of file diff --git a/app/assets/stylesheets/inc/_modals.css.scss b/app/assets/stylesheets/inc/_modals.css.scss index ce251ac..dbed5a5 100644 --- a/app/assets/stylesheets/inc/_modals.css.scss +++ b/app/assets/stylesheets/inc/_modals.css.scss @@ -245,6 +245,14 @@ } .add { @include btn-upload(44px); + &._ajax { + background: #FFD491; + border-color: #F7BB5F; + @include text-shadow(0 0px 1px rgba(0, 0, 0, 0.6)); + span { + background: asset_url("btn-loading.gif", image) no-repeat right 0;; + } + } } } .error-block { @@ -256,8 +264,11 @@ #upload_image_botton { float: right; } - } - &.add_fun_form { + .column2 { + width: 230px; + margin-bottom: 5px; + #upload_image_botton { float: none; } + } .__ajax { position: absolute; top: 0; @@ -268,19 +279,6 @@ z-index: 1000; background: url('/assets/__loading.gif') no-repeat center rgba(255, 255, 255, .45); } - .modal_footer { - .add { - @include btn-upload(44px); - &._ajax { - background: #FFD491; - border-color: #F7BB5F; - @include text-shadow(0 0px 1px rgba(0, 0, 0, 0.6)); - span { - background: asset_url("btn-loading.gif", image) no-repeat right 0;; - } - } - } - } } } @@ -395,6 +393,18 @@ width: 112px; padding: 3px 18px; } + .column2 { + .url { width: 228px; } + input { + width: 228px; + &.url { width: 188px; } + } + .btn-file { width: 192px; } + } + .full-width { + width: 100%; + input.url { width: 430px } + } } #add_video { .url { diff --git a/app/controllers/funs_controller.rb b/app/controllers/funs_controller.rb index d7a83cc..fcdfb63 100644 --- a/app/controllers/funs_controller.rb +++ b/app/controllers/funs_controller.rb @@ -46,6 +46,8 @@ def new # GET /funs/1/edit def edit @fun = Fun.find(params[:id]) + + render layout: false if request.xhr? end # POST /funs @@ -65,10 +67,14 @@ def create # PUT /funs/1 def update - if @fun.content.update_attributes(params[:fun][:content_attributes]) - redirect_to @fun, notice: t('funs.updated') - else - render 'edit' + respond_to do |format| + if @fun.content.update_attributes(params[:fun][:content_attributes]) + format.html { redirect_to @fun, notice: t('funs.updated') } + format.json { render json: { success: true, path: fun_path(@fun) } } + else + format.html { render 'edit' } + format.json { render json: { success: false, notice: t('funs.update_error') } } + end end end diff --git a/app/views/funs/edit.html.slim b/app/views/funs/edit.html.slim index 75df0af..04355ed 100644 --- a/app/views/funs/edit.html.slim +++ b/app/views/funs/edit.html.slim @@ -1,13 +1,15 @@ -.container.page-layout - h1 Редактирование фана - .profile_layout - section.content[role='main'] - = simple_form_for @fun, url: fun_path(@fun), html: { method: :put, class: 'form-horizontal', id: 'new_fun' }, validate: true do |fun| - = fun.input :content_type, as: :hidden, wrapper: :none - = fun.simple_fields_for :content_attributes, @fun.content, validate: true do |f| - = render "funs/#{@fun.content_type.downcase.pluralize}/edit", f: f +/* ********** MODAL **************** */ +/* edit fun */ +.modal.add_fun_form + .modal_header Редактирование фана + .modal_body + .tabs_box + .tab_content + = simple_form_for @fun, url: fun_path(@fun), wrapper: :none, remote: true, html: {:'data-type' => 'json', id: 'edit_fun'}, validate: true do |form| + div.tab_pane.active= render "funs/#{@fun.content_type.downcase.pluralize}/edit", fun: @fun, form: form + .modal_footer + a.cancel[href="#"] Отменить + a.add[href="#" rel='submit' data-form='#edit_fun']:span Сохранить - .divider - .control-group - .controls - a.save[href='#' rel='submit']Сохранить \ No newline at end of file +javascript: + $('#edit_fun').enableClientSideValidations(); \ No newline at end of file diff --git a/app/views/funs/images/_edit.html.slim b/app/views/funs/images/_edit.html.slim index 89bede0..33acc3f 100644 --- a/app/views/funs/images/_edit.html.slim +++ b/app/views/funs/images/_edit.html.slim @@ -1,19 +1,21 @@ -= f.input :title, :validate => { :presence => true } -.control-row - = f.input :remote_file_url - .help-inline или - span.fileupload-new#upload_image_botton - span.btn-file - span.fileupload-preview - span.fileupload-new Загрузить - = f.file_field :file, accept: 'image/jpeg,image/png,image/gif', validate: false, wrapper: :none += form.simple_fields_for :content_attributes, fun.content do |f| + = f.input :title + .column2.pull-right.control-row + span.fileupload-new#upload_image_botton + span.btn-file + span.fileupload-preview + span.fileupload-new Загрузить + = f.file_field :file, accept: 'image/jpeg,image/png,image/gif', validate: false, wrapper: :none + .text-center.vertical-space-sm или + = f.input :remote_file_url + .column2= fun_image(@fun, version: :small) -= f.input :tag_list + = f.input :tag_list javascript: $('#upload_image_botton').inputfileupload({ maxFileSize: 15000000, onFailMaxSize: function(){ - $('#upload_image_botton').closest('.control-row').append($('
Размер файла больше допустимого, попробуйте загрузить меньшего размера.
')) + $('#upload_image_botton').closest('.column2').append($('
Размер файла больше допустимого, попробуйте загрузить меньшего размера.
')) } }); diff --git a/app/views/funs/posts/_edit.html.slim b/app/views/funs/posts/_edit.html.slim index 9bd6d00..615b89b 100644 --- a/app/views/funs/posts/_edit.html.slim +++ b/app/views/funs/posts/_edit.html.slim @@ -1,3 +1,4 @@ -= f.input :title -= f.input :body, validate: true -= f.input :tag_list \ No newline at end of file += form.simple_fields_for :content_attributes, fun.content do |f| + = f.input :title + = f.input :body + = f.input :tag_list \ No newline at end of file diff --git a/app/views/funs/show.html.slim b/app/views/funs/show.html.slim index d86cdd8..5f6d1be 100644 --- a/app/views/funs/show.html.slim +++ b/app/views/funs/show.html.slim @@ -14,6 +14,7 @@ span.date_block = time_ago_in_words @fun.created_at | назад + = link_to 'edit', edit_fun_path(@fun), class: 'fancybox_ajax' - if @fun.content.title? h1.title = title @fun.content.title diff --git a/app/views/funs/videos/_edit.html.slim b/app/views/funs/videos/_edit.html.slim index 516fe5f..21224d2 100644 --- a/app/views/funs/videos/_edit.html.slim +++ b/app/views/funs/videos/_edit.html.slim @@ -1,3 +1,5 @@ -= f.input :title -= f.input :url -= f.input :tag_list += form.simple_fields_for :content_attributes, fun.content do |f| + = f.input :title + .text-center= fun_image(@fun, version: :small) + = f.input :url, wrapper_html: { class: 'full-width' } + = f.input :tag_list \ No newline at end of file diff --git a/app/views/layouts/_header.html.slim b/app/views/layouts/_header.html.slim index f127815..8d9bbcf 100644 --- a/app/views/layouts/_header.html.slim +++ b/app/views/layouts/_header.html.slim @@ -8,7 +8,7 @@ header.main_panel[role="banner"] .item_outer - data = user_signed_in? ? {} : {:'data-auth' => 'true'} .item.add_fun - a.item_link.link_new_fun *data href="#{new_fun_path}" + a.item_link.fancybox_ajax *data href="#{new_fun_path}" span.span_cell Добавить фан .item_outer = link_to_users diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 965b5b4..b314c71 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -71,6 +71,7 @@ ru: followers: "Количество подписчиков" created_at: "Дата регистрации" social_likes: "Проголосовать в соц сетях" + update_error: "Произошла ошибка при сохранении фана :( Проверьте данные и повторите попытку" reposts: created: "Фан успешно скопирован вам на стену." button: "Репостить" From f9ccb41c542b1a4824e85f30b7f6aa3c8687c625 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Thu, 10 Apr 2014 14:35:17 +0300 Subject: [PATCH 05/64] fix in_sandbox& method --- app/models/fun.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/fun.rb b/app/models/fun.rb index fc9821d..106aeb1 100644 --- a/app/models/fun.rb +++ b/app/models/fun.rb @@ -110,7 +110,7 @@ def unlike_by(user) end def in_sandbox? - !published_at.nil? + published_at.nil? end # get related funs without funs liked by user From 6b5f8eb008430af84fbd3e5300e2e2f0c6ef7de5 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Thu, 10 Apr 2014 14:37:02 +0300 Subject: [PATCH 06/64] refactoring destroy rule --- app/models/ability.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index 02158f2..89b5a6f 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -8,11 +8,9 @@ def initialize(user) elsif user.role? :user can [:create, :feed, :autocomplete_tags], Fun can :destroy, Fun do |fun| - fun.user_id == user.id && if fun.repost? - true - else - fun.repost_counter == 0 && ! fun.published_at - end + fun.user_id == user.id && ( + fun.repost? || (fun.repost_counter == 0 && ! fun.in_sandbox?) + ) end can :create, :repost can [:create, :destroy], [UserRelationship, :like] From 96eb2a787f67f649efd2dcc899a85457faee6383 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Thu, 10 Apr 2014 16:33:41 +0300 Subject: [PATCH 07/64] fun edit/delete buttons --- app/assets/images/btn-fun-delete.png | Bin 2315 -> 0 bytes app/assets/images/btn-fun-icons.png | Bin 0 -> 2317 bytes app/assets/stylesheets/funs.css.scss | 21 ++++++++++++++++---- app/assets/stylesheets/inc/_modals.css.scss | 9 +++++++++ app/helpers/funs_helper.rb | 11 +++++++++- app/views/funs/edit.html.slim | 8 ++++++-- app/views/funs/show.html.slim | 4 ++-- config/locales/ru.yml | 3 +++ 8 files changed, 47 insertions(+), 9 deletions(-) delete mode 100644 app/assets/images/btn-fun-delete.png create mode 100644 app/assets/images/btn-fun-icons.png diff --git a/app/assets/images/btn-fun-delete.png b/app/assets/images/btn-fun-delete.png deleted file mode 100644 index 290766949d1a9bbc28ccd467c4bebe2464cd2f55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2315 zcmaJ>eK=HUA0A1U6wyf3mg5LZ=F?2m%$gL()MTbK$VV?3Glv<>oH28l@zGl8LqgGN zYFWy*+U=!K+ZSG&LcUU~6st&xMDj-2ls($C?;mgbT-Q0z$93QL@Av$E_w^j`+_KTo zV3`39hco1Ef&|#?h<#@I^RRz8{B;91S)lHIs2387s)b4zw?T}AzyMb!41)!*P#hao z4?E*wb z%vZR<66vNmCF~Wq#ak2?A!3R_mvw-%hJ^{pU{nZbWRY?eOTz{~=(4c&%rOZBK0we2 zHuzUketb{B4N<}Xok%8#$ZIIT8XA#8BQt4CM}SJEkVzCOiOe8S$SgX8MWz5B2Z%*e zibGifi1RTPwqt`56jiWDB(+*iR67w7Wf+OVWHL!)Dv3%ZU;gbEUcNS?XUERfItXQ)i}39Ui} z@Zb6VUtyJZtO6zpU=;H3V&+XFcVv^O}rM%yh9NF3{@>X*ZiY6ne#vSYBOLQeM?{Jn{YTXt}Zes=VGOmbZ>OO*6t;nwT#4Y3Vju z85u?y`}x%dey8l`K}ji4j~-7D7}#uNZDV88BmF&D;&9mLl#c!StlTogJxRtTI*}{) zyb;!ff)Sa$)THOBsi|cJ1qJ})G)vYl$USmZ7;Ji3XR0K}njvt_`Z1-yuebLLL?Y3UJmOLAe`6@J_eP@CuhB!D zt!ZC{o2wb;aV~A`_wTEtv7vJmws`qqrG3<5$b8EaUg)jptsTJ&yY16_E3a3( z7bkmocrfDP?L-L+?LFfs zc>b3rp6p0@)&iuS*g;_V*ZX=}{kCl`)y(ZezG$kZ<-x-{r3>(Q{2TiR*2kYZ_@_Q6 zXdCG{+1Wnl^K<9Vouf`zw^L`|xT!R`#GT{YOBfrc%Led=EARx>KA*bIhRStaI5hzSE}7ycc0&{<>QHfk_7=51RyZRAV5WXf zZmxJ}XebJ#*{*0`m~?1=0wtlIx0c}IQpGJ##D8~eRkg*rcjhiv_WL{U3~sd3lkiw& zHH>+dV}viilw@7``O!LA%H8}i;?kb+xc0Fz>T*lVrO^BtHPg~+wOPykdlBhoo3BZW zTN7OB6Yi0&ke_gNdQ|zJ{-LlzAKz! zm@S+)m}(03Mb|5$4RRbto9j4v0&B;Dg;8aR?*&HY?~C}Qe$zR-PXG?}27%p4>*|0N z0np|h!-Z!yDM2Q){l~1EH*W^__4VxrOz1bWG9u6Xs%>*VxwwC$V0Xy2P%zFrgl@^Y zvwXdo-#)LZGFoh6eJ&l0fLM90y!eFXYraJ%Ut5H~9F@srllQdCm=RE0%7x5UOeHmC zs|~M?nzq^L*T9urKfCJ2u1A^k!sGOFHkfs9ZS(qN*|#>VGZiYFd-tO38=ak<88pw< zWGwz`tCdy9<|9qFZpCc70#gnK)#HXIHeL>UYx&f1z38`0eiL5rMztmiU-`T+G8GIz zSXNfnBVas^DfbTw3UUrh&z&jlfoiSMzv>e852d9|nO$I3JvkkKF5aU!EPeMPBeG*v>Y&lXZ0 zF1=+-Y1#y_OX-u_7HoMiioP0g>zc|gdD;Oa{-Im3#^27?_{ibu>l~GYIC|fq7GCMq<*lfweAV@+J&2Xh=EYAgX($f7s5LSz^777z z3J&w+O{F}KQUp|2G?rh~#?wdl?%jJX_)hpQNp(GLPEJl;D^Ddcc7fZF+pa#wKOMeG ziCw-bvKznnQ6JtuP+q;((1a_00_1PnIL@zIG-?v=ojWi+Y4XQ8oGvc#VXvLZF(LL8 P<8WN}Eznul;N5=$J?YC2 diff --git a/app/assets/images/btn-fun-icons.png b/app/assets/images/btn-fun-icons.png new file mode 100644 index 0000000000000000000000000000000000000000..147124c892f7a5330fca72f53865405219b893a9 GIT binary patch literal 2317 zcmV+o3G()dP)v&1+pd>aXq-vVb+}N~92>r8#WSx-O$BJ~6p+zgxB-9nu zp)m;_881KuQo|uiz%_(4j*Duo~S0D8^ShpaD4`*V)-Axs6RM0=fby z1{{DLC^DwZ09hadOaa$#C%Bjgs~B)4z{)@%&`?uTvtz}I70pFOMYRAkGcy;jU%&p* z;Nalla5y{wTmw=-wzIQSU&^A9NMsA}6JR~iYz%({^a1axs`~e@1vX%dfijoNRoT|o z_N!9)7&&$xCO^whbgxBtS`c+RNQ%4O?(Xh>Es;o!194z#G3ZDnvIaOHgz&gr zuGq?zD=QohM;$;WlZjrtc5Nb&Ncg0bW56y|RWB_FY{;M(C~t3X-(Fr`{-}NMoeeV7 z1u_eY0AcJ+O3)<;JEHL^vNbzT3XuTcDo0F1M?$n1)PnIjq6HsqaE_IxAPLPC}1x^wC)F2U4Bdv;Ht}y*-P?s z6b1ROKT)DhbgWyqE&w>qQI13+TZIr_kH_ zcv^)J-bf_!@O)rLb#?V4^5RiYbOS^nHoS=Nw4$`W0i|o8bPY=D8wgJ;V#A9!Hm2yv zi$__tYSkmg-))w~Pu*_!zl~fDKr|X99*@)C-%mQ7CY?^x-``I>9w!=&ngeQayWK;; z&k6&DOTq4NI5x@HKl6u62oNA6e?XMo4|aDR8o=&`>?CsF_xU4h%$Kns#f{HwGUR13 zE&8C#z8uzK)GNM6d%DL`i?uvjeR^KM0edu=wG&kW&oI`RAc6crUQGcz*_ z>-YO{I-PTXZ8lpuaIYCyd@EOwt}zev+iI5ihfW7HP1DA4dh>Z!0?1j-79v}S^sJ^a z=1K`pFPf%}8+C^H@`z1OPmh`xEoin7*+QfXnl`uT>FF^bW(Ljy*-R#LR`^;C;5>-% z@0lY5vpj@<&ka~95qEDUlgacNb%thI^K2rK_}mOJJUl!{24;B-4-d})P9zc|zz6ez zr-p`x4vV@Spey;COqa-W&m+fzH#D2PgdThnITl2odp+3z{w~E2FNi&djS#PEOtfy!92}P$=|i%IZBL?t3&3q3MuK zA%jmtB09SX64CrvHf6v{#M;M5S-nR>q0lEl+6=6!>Io@jdVG95IGdWRR#a7;bHJQV zC#tGqwcf~xw!)f2P8#=UeZ`%>~J_9FcZDv`nIU0>}=FA!Vem_-JRRjV7B9RF7_4S0qVV-#6iCcHg zsq4_yt#JCH;PgcWp9?}Gd3V|Wg<$Uwbt+13-8H9DDfaK*tpNIt*ENHJlFie=lOIyk%EWTNG^;EdM+z8RY{tvOy$rmy5`>A zUTiiS6B84(wY72K!UcMIdT4HLrn$NKEC0xnUGw{c3LWbu|A-0>^$IG!2M?{$X{k0{ zV#{#NJv}{ibaZg?O10OGI>50i>(4$ n%|`T&Yrf-}@3`jM?3(`vGwQ_9Lfj}Y00000NkvXXu0mjfIaXbz literal 0 HcmV?d00001 diff --git a/app/assets/stylesheets/funs.css.scss b/app/assets/stylesheets/funs.css.scss index 7cde8bb..e3df09e 100644 --- a/app/assets/stylesheets/funs.css.scss +++ b/app/assets/stylesheets/funs.css.scss @@ -872,7 +872,7 @@ html, body { } &:hover { a.btn-fun-delete { - background: asset_url("btn-fun-delete.png", image) no-repeat -21px 0; + background: asset_url("btn-fun-icons.png", image) no-repeat -22px 0; height: 21px; width: 21px; position: absolute; @@ -880,7 +880,7 @@ html, body { right: -8px; z-index: 1001; &:hover { - background: asset_url("btn-fun-delete.png", image) no-repeat 0 0; + background: asset_url("btn-fun-icons.png", image) no-repeat 0 0; cursor: pointer; } } @@ -2188,7 +2188,7 @@ html, body { &:hover{ a { &.btn-fun-delete{ - background: asset_url("btn-fun-delete.png", image) no-repeat -21px 0; + background: asset_url("btn-fun-icons.png", image) no-repeat -22px 0; height: 21px; width: 21px; position: absolute; @@ -2196,7 +2196,20 @@ html, body { right: -8px; z-index: 1001; &:hover{ - background: asset_url("btn-fun-delete.png", image) no-repeat 0 0; + background: asset_url("btn-fun-icons.png", image) no-repeat 0 0; + cursor: pointer; + } + } + &.btn-fun-edit{ + background: asset_url("btn-fun-icons.png", image) no-repeat -22px -22px; + height: 21px; + width: 21px; + position: absolute; + top: -8px; + right: -8px; + z-index: 1001; + &:hover{ + background: asset_url("btn-fun-icons.png", image) no-repeat 0 -22px; cursor: pointer; } } diff --git a/app/assets/stylesheets/inc/_modals.css.scss b/app/assets/stylesheets/inc/_modals.css.scss index dbed5a5..13bd115 100644 --- a/app/assets/stylesheets/inc/_modals.css.scss +++ b/app/assets/stylesheets/inc/_modals.css.scss @@ -254,6 +254,15 @@ } } } + .inner_wrapper { + padding: 0 15px; + a { + margin-right: 0; + & + a { + margin-left: 15px; + } + } + } } .error-block { margin-bottom: 0; diff --git a/app/helpers/funs_helper.rb b/app/helpers/funs_helper.rb index 16e3ce8..8dbd04e 100644 --- a/app/helpers/funs_helper.rb +++ b/app/helpers/funs_helper.rb @@ -140,9 +140,18 @@ def fun_add_line(fun, link = false) end end + def edit_fun_link(fun, options = nil, text = '') + if can? :update, fun + data = { class: 'btn-fun-edit fancybox_ajax', rel: 'tooltip', title: t('funs.titles.edit') } + data.merge! options if options.is_a? Hash + + link_to text, edit_fun_path(fun), data + end + end + def remove_fun_link(fun) if can? :destroy, fun - link_to '', url_for(action: 'show', controller: 'funs', id: fun), class: 'btn-fun-delete', method: :delete, remote: true, data: { type: :json }, confirm: t('funs.confirm.delete') , rel: 'tooltip', title: t('funs.titles.delete') + link_to '', fun, class: 'btn-fun-delete', method: :delete, remote: true, data: { type: :json }, confirm: t('funs.confirm.delete') , rel: 'tooltip', title: t('funs.titles.delete') end end diff --git a/app/views/funs/edit.html.slim b/app/views/funs/edit.html.slim index 04355ed..ab10ad4 100644 --- a/app/views/funs/edit.html.slim +++ b/app/views/funs/edit.html.slim @@ -8,8 +8,12 @@ = simple_form_for @fun, url: fun_path(@fun), wrapper: :none, remote: true, html: {:'data-type' => 'json', id: 'edit_fun'}, validate: true do |form| div.tab_pane.active= render "funs/#{@fun.content_type.downcase.pluralize}/edit", fun: @fun, form: form .modal_footer - a.cancel[href="#"] Отменить - a.add[href="#" rel='submit' data-form='#edit_fun']:span Сохранить + .inner_wrapper + - if can? :destroy, @fun + = link_to t('global.delete'), @fun, class: 'cancel pull-left', method: :delete, confirm: t('funs.confirm.delete') + + a.cancel[href="#"] Отменить + a.add[href="#" rel='submit' data-form='#edit_fun']:span Сохранить javascript: $('#edit_fun').enableClientSideValidations(); \ No newline at end of file diff --git a/app/views/funs/show.html.slim b/app/views/funs/show.html.slim index 5f6d1be..ada5406 100644 --- a/app/views/funs/show.html.slim +++ b/app/views/funs/show.html.slim @@ -1,5 +1,5 @@ - fun_meta(@fun) -= render "layouts/social_plugin" += render 'layouts/social_plugin' .container.post_layout section.content[role="main"] article.post_frame.load_buttons @@ -14,7 +14,6 @@ span.date_block = time_ago_in_words @fun.created_at | назад - = link_to 'edit', edit_fun_path(@fun), class: 'fancybox_ajax' - if @fun.content.title? h1.title = title @fun.content.title @@ -26,6 +25,7 @@ a[href="https://twitter.com/share" rel="nofollow" class="twitter-share-button" data-via="bitfun" data-lang="ru" data-related="butfun" data-text="#{@fun.content.title || t('meta_tags.main.title')}"] Tweet .follow_parent = follow_link(@fun.user) + = edit_fun_link @fun .post_object = render_fun_partial @fun, :show .post_nav diff --git a/config/locales/ru.yml b/config/locales/ru.yml index b314c71..12c6486 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -1,4 +1,6 @@ ru: + global: + delete: Удалить activerecord: errors: models: @@ -71,6 +73,7 @@ ru: followers: "Количество подписчиков" created_at: "Дата регистрации" social_likes: "Проголосовать в соц сетях" + edit: "Редактировать фан" update_error: "Произошла ошибка при сохранении фана :( Проверьте данные и повторите попытку" reposts: created: "Фан успешно скопирован вам на стену." From ac4c0d5408d816d050e22c79ca344683db29fb4a Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Fri, 11 Apr 2014 10:35:20 +0300 Subject: [PATCH 08/64] refresh cloud tags --- app/controllers/funs_controller.rb | 2 +- app/views/funs/_tag_cloud.html.slim | 2 +- app/views/funs/index.html.slim | 3 ++- app/views/funs/index.js.erb | 5 +++++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/controllers/funs_controller.rb b/app/controllers/funs_controller.rb index fcdfb63..b6deeb5 100644 --- a/app/controllers/funs_controller.rb +++ b/app/controllers/funs_controller.rb @@ -13,7 +13,7 @@ def index if params[:query] funs_ids = Fun.search_fun_ids(params[:query], type) @funs = @funs.where(id: funs_ids) - @tags = Fun.create_tag_cloud type + @tags = Fun.create_tag_cloud type if (params[:page].nil? || !request.xhr?) end cookies_store.set params.select { |k,v| k.in? %w(type view interval sort) } diff --git a/app/views/funs/_tag_cloud.html.slim b/app/views/funs/_tag_cloud.html.slim index 3d8a59b..22c9161 100644 --- a/app/views/funs/_tag_cloud.html.slim +++ b/app/views/funs/_tag_cloud.html.slim @@ -1,2 +1,2 @@ -- tag_cloud(@tags, %w(small middle big biggest)) do |tag, css_class| +- tag_cloud(tags, %w(small middle big biggest)) do |tag, css_class| = link_to tag.name, search_tags_path(query: tag.name), class: "#{css_class} tags" \ No newline at end of file diff --git a/app/views/funs/index.html.slim b/app/views/funs/index.html.slim index ea64480..e2bff83 100644 --- a/app/views/funs/index.html.slim +++ b/app/views/funs/index.html.slim @@ -13,7 +13,8 @@ .icon-search a.find.btn[href="#"] Искать .clearfix - = render 'tag_cloud' + - if @tags + #bitfun_cloud_wrapper= render 'tag_cloud', tags: @tags div *data class="container main_layout#{view_partial == 'box' ? ' grid' : ''}" section.content[role="main"] diff --git a/app/views/funs/index.js.erb b/app/views/funs/index.js.erb index 9214497..f44f2b4 100644 --- a/app/views/funs/index.js.erb +++ b/app/views/funs/index.js.erb @@ -9,4 +9,9 @@ elsif ! params[:page] content << render('funs/empty') end %> +<%if @tags%> + <%= javascript_tag do %> + $('#bitfun_cloud_wrapper').html('<%= render 'tag_cloud', tags: @tags%>'); + <%end%> +<%end%> <%= content.html_safe %> \ No newline at end of file From 0b7d9a3e19dc3add012505bf411f111c1e2e34c4 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Fri, 11 Apr 2014 10:52:19 +0300 Subject: [PATCH 09/64] fix fun destroy rule --- app/models/ability.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index 89b5a6f..57a211d 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -9,7 +9,7 @@ def initialize(user) can [:create, :feed, :autocomplete_tags], Fun can :destroy, Fun do |fun| fun.user_id == user.id && ( - fun.repost? || (fun.repost_counter == 0 && ! fun.in_sandbox?) + fun.repost? || (fun.repost_counter == 0 && fun.in_sandbox?) ) end can :create, :repost From ef2068702d07c3d3a87ec1d626eac0c9f3d68c0a Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Mon, 14 Apr 2014 09:37:08 +0300 Subject: [PATCH 10/64] notification model --- app/models/notification.rb | 12 ++++++++++++ .../20140411085401_create_notifications.rb | 16 ++++++++++++++++ db/schema.rb | 14 +++++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 app/models/notification.rb create mode 100644 db/migrate/20140411085401_create_notifications.rb diff --git a/app/models/notification.rb b/app/models/notification.rb new file mode 100644 index 0000000..b47f883 --- /dev/null +++ b/app/models/notification.rb @@ -0,0 +1,12 @@ +class Notification < ActiveRecord::Base + attr_accessible :target_id, :target_type, + :target, :action, + :user_id + + belongs_to :target, polymorphic: true + belongs_to :user + + validates_presence_of :target_id + validates_presence_of :user_id + validates_presence_of :action +end diff --git a/db/migrate/20140411085401_create_notifications.rb b/db/migrate/20140411085401_create_notifications.rb new file mode 100644 index 0000000..a7b26ca --- /dev/null +++ b/db/migrate/20140411085401_create_notifications.rb @@ -0,0 +1,16 @@ +class CreateNotifications < ActiveRecord::Migration + def change + create_table :notifications do |t| + + t.string :action + t.references :target, polymorphic: true + t.integer :user_id + t.integer :receiver_id + + t.timestamp :created_at + end + + add_index :notifications, [:target_id, :target_type] + add_index :notifications, :user_id + end +end diff --git a/db/schema.rb b/db/schema.rb index 66ba574..8112d60 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130906075059) do +ActiveRecord::Schema.define(:version => 20140411085401) do create_table "funs", :force => true do |t| t.integer "user_id" @@ -47,6 +47,18 @@ t.string "cached_tag_list" end + create_table "notifications", :force => true do |t| + t.string "action" + t.integer "target_id" + t.string "target_type" + t.integer "user_id" + t.integer "receiver_id" + t.datetime "created_at" + end + + add_index "notifications", ["target_id", "target_type"], :name => "index_notifications_on_target_id_and_target_type" + add_index "notifications", ["user_id"], :name => "index_notifications_on_user_id" + create_table "posts", :force => true do |t| t.string "title" t.text "body" From ce7d0092d13c169ed19158fd440597ad57fb3ce8 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Mon, 14 Apr 2014 09:37:46 +0300 Subject: [PATCH 11/64] create notification on fun create --- app/models/fun.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/models/fun.rb b/app/models/fun.rb index 106aeb1..2d9baee 100644 --- a/app/models/fun.rb +++ b/app/models/fun.rb @@ -4,6 +4,7 @@ class Fun < ActiveRecord::Base after_destroy :delete_content before_destroy :delete_likes before_destroy :delete_reposts + after_create :create_notification # Kaminari pagination config paginates_per 10 @@ -20,6 +21,7 @@ class Fun < ActiveRecord::Base belongs_to :content, polymorphic: true accepts_nested_attributes_for :content, allow_destroy: true has_many :reports, dependent: :destroy + has_many :notifications, as: :target, dependent: :destroy # Reposts has_many :reposts, class_name: 'Fun', foreign_key: 'parent_id' @@ -217,4 +219,10 @@ def delete_reposts def delete_content content.destroy unless repost? end + + private + + def create_notification + self.notifications.create(user_id: user_id, action: :create) + end end \ No newline at end of file From 8119f04f0e568777c59233f88b4dfc42a1a44467 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Mon, 14 Apr 2014 11:29:01 +0300 Subject: [PATCH 12/64] fix fancybox popup bug --- app/assets/javascripts/application.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index f7c30f1..6a69b7c 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -146,7 +146,12 @@ $(function(){ $('.fancybox_ajax').not('[data-auth]').fancybox({ type: 'ajax', - padding : 0 + padding : 0, + helpers: { + overlay: { + locked: false + } + } }); }); From 391aa54e589cde06e19e1f114e6481d5d4b166e0 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Mon, 14 Apr 2014 11:33:48 +0300 Subject: [PATCH 13/64] extend vote model --- lib/acts_as_votable/vote.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 lib/acts_as_votable/vote.rb diff --git a/lib/acts_as_votable/vote.rb b/lib/acts_as_votable/vote.rb new file mode 100644 index 0000000..3557b83 --- /dev/null +++ b/lib/acts_as_votable/vote.rb @@ -0,0 +1,15 @@ +module ActsAsVotable + class Vote < ActiveRecord::Base + + after_create :create_notification + has_many :notifications, as: :target, dependent: :destroy + + private + + def create_notification + notifications.create(user_id: voter_id, action: :create, receiver_id: votable.user_id) + end + + end + +end \ No newline at end of file From 4cc34f1ff5d5c5f0133b732f245a1cc9cb2d9580 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Mon, 14 Apr 2014 11:34:22 +0300 Subject: [PATCH 14/64] add field to notification --- app/models/notification.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/notification.rb b/app/models/notification.rb index b47f883..ad47fc5 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -1,7 +1,7 @@ class Notification < ActiveRecord::Base attr_accessible :target_id, :target_type, :target, :action, - :user_id + :user_id, :receiver_id belongs_to :target, polymorphic: true belongs_to :user From 67b7cffad36d1b8178641fa5d083ee8ac9eb0de6 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Mon, 14 Apr 2014 11:35:33 +0300 Subject: [PATCH 15/64] change autoload from lib --- config/initializers/autoload.rb | 10 ++++++++++ config/initializers/carrierwave.rb | 3 --- 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 config/initializers/autoload.rb delete mode 100644 config/initializers/carrierwave.rb diff --git a/config/initializers/autoload.rb b/config/initializers/autoload.rb new file mode 100644 index 0000000..5032c53 --- /dev/null +++ b/config/initializers/autoload.rb @@ -0,0 +1,10 @@ +dirs = [ + %w'lib acts_as_votable', + %w'lib carrierwave processing' +] + +dirs.each do |folders| + dir = Rails.root.join *folders + $LOAD_PATH.unshift(dir) + Dir[File.join(dir, '*.rb')].each {|file| require File.basename(file) } +end \ No newline at end of file diff --git a/config/initializers/carrierwave.rb b/config/initializers/carrierwave.rb deleted file mode 100644 index 3adb31c..0000000 --- a/config/initializers/carrierwave.rb +++ /dev/null @@ -1,3 +0,0 @@ -dir = Rails.root.join('lib', 'carrierwave/processing') -$LOAD_PATH.unshift(dir) -Dir[File.join(dir, "*.rb")].each {|file| require File.basename(file) } \ No newline at end of file From bfbd7eb417c34f75994b159c405cf78a512f9d7b Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 15 Apr 2014 11:16:29 +0300 Subject: [PATCH 16/64] notification list --- app/controllers/notifications_controller.rb | 7 +++++++ app/models/ability.rb | 1 + app/models/fun.rb | 2 +- app/models/notification.rb | 9 +++++---- app/views/notifications/index.html.slim | 8 ++++++++ config/routes.rb | 2 ++ db/migrate/20140411085401_create_notifications.rb | 3 ++- db/schema.rb | 4 +++- lib/acts_as_votable/vote.rb | 5 +++-- 9 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 app/controllers/notifications_controller.rb create mode 100644 app/views/notifications/index.html.slim diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb new file mode 100644 index 0000000..5df5838 --- /dev/null +++ b/app/controllers/notifications_controller.rb @@ -0,0 +1,7 @@ +class NotificationsController < ApplicationController + authorize_resource + + def index + @notifications = Fun.unscoped { Notification.includes(:user, :target, :subject).all } + end +end diff --git a/app/models/ability.rb b/app/models/ability.rb index 57a211d..0f289c1 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -19,6 +19,7 @@ def initialize(user) can :create, Report can :read, :all cannot [:destroy, :read], Report + cannot :show, Notification else can :read, :all end diff --git a/app/models/fun.rb b/app/models/fun.rb index 2d9baee..e54733e 100644 --- a/app/models/fun.rb +++ b/app/models/fun.rb @@ -21,7 +21,7 @@ class Fun < ActiveRecord::Base belongs_to :content, polymorphic: true accepts_nested_attributes_for :content, allow_destroy: true has_many :reports, dependent: :destroy - has_many :notifications, as: :target, dependent: :destroy + has_many :notifications, as: :subject, dependent: :destroy # Reposts has_many :reposts, class_name: 'Fun', foreign_key: 'parent_id' diff --git a/app/models/notification.rb b/app/models/notification.rb index ad47fc5..89d5aa9 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -1,12 +1,13 @@ class Notification < ActiveRecord::Base - attr_accessible :target_id, :target_type, - :target, :action, - :user_id, :receiver_id + attr_accessible :target_id, :target_type, :target, + :subject_id, :subject_type, :subject, + :action, :user_id, :receiver_id + belongs_to :subject, polymorphic: true belongs_to :target, polymorphic: true belongs_to :user - validates_presence_of :target_id + validates_presence_of :subject_id validates_presence_of :user_id validates_presence_of :action end diff --git a/app/views/notifications/index.html.slim b/app/views/notifications/index.html.slim new file mode 100644 index 0000000..276b9e4 --- /dev/null +++ b/app/views/notifications/index.html.slim @@ -0,0 +1,8 @@ +.container.rating_layout + .topics_block + .title_page + h1 Notification list + .rating_layout + ul + - @notifications.each do |n| + li #{link_to(n.user.login, n.user)} #{n.action} #{n.subject.class.name} #{link_to n.target.class.name, n.target if n.target} #{n.created_at} \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 72333b4..402b8ef 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,6 +2,8 @@ root to: 'funs#index' + resources :notifications, only: :index + get 'reports', to: 'reports#index' resources :funs do resources :reports, except: :index diff --git a/db/migrate/20140411085401_create_notifications.rb b/db/migrate/20140411085401_create_notifications.rb index a7b26ca..8bd35e4 100644 --- a/db/migrate/20140411085401_create_notifications.rb +++ b/db/migrate/20140411085401_create_notifications.rb @@ -3,6 +3,7 @@ def change create_table :notifications do |t| t.string :action + t.references :subject, polymorphic: true t.references :target, polymorphic: true t.integer :user_id t.integer :receiver_id @@ -10,7 +11,7 @@ def change t.timestamp :created_at end - add_index :notifications, [:target_id, :target_type] + add_index :notifications, [:subject_id, :subject_type] add_index :notifications, :user_id end end diff --git a/db/schema.rb b/db/schema.rb index 8112d60..a83a27a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -49,6 +49,8 @@ create_table "notifications", :force => true do |t| t.string "action" + t.integer "subject_id" + t.string "subject_type" t.integer "target_id" t.string "target_type" t.integer "user_id" @@ -56,7 +58,7 @@ t.datetime "created_at" end - add_index "notifications", ["target_id", "target_type"], :name => "index_notifications_on_target_id_and_target_type" + add_index "notifications", ["subject_id", "subject_type"], :name => "index_notifications_on_subject_id_and_subject_type" add_index "notifications", ["user_id"], :name => "index_notifications_on_user_id" create_table "posts", :force => true do |t| diff --git a/lib/acts_as_votable/vote.rb b/lib/acts_as_votable/vote.rb index 3557b83..7b33262 100644 --- a/lib/acts_as_votable/vote.rb +++ b/lib/acts_as_votable/vote.rb @@ -2,12 +2,13 @@ module ActsAsVotable class Vote < ActiveRecord::Base after_create :create_notification - has_many :notifications, as: :target, dependent: :destroy + has_many :notifications, as: :subject, dependent: :destroy private def create_notification - notifications.create(user_id: voter_id, action: :create, receiver_id: votable.user_id) + notifications.create(user_id: voter_id, action: :create, + receiver_id: votable.user_id, target: votable) end end From 89811a392e8de17966def06bae788f76e6affcd2 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 15 Apr 2014 11:19:32 +0300 Subject: [PATCH 17/64] show only my notifications --- app/controllers/notifications_controller.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb index 5df5838..3f305cf 100644 --- a/app/controllers/notifications_controller.rb +++ b/app/controllers/notifications_controller.rb @@ -2,6 +2,8 @@ class NotificationsController < ApplicationController authorize_resource def index - @notifications = Fun.unscoped { Notification.includes(:user, :target, :subject).all } + @notifications = Fun.unscoped do + Notification.includes(:user, :target, :subject).where(receiver_id: current_user.id) + end end end From 197e580447baaf2f28d46b7718001312d2fbff86 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 15 Apr 2014 15:30:12 +0300 Subject: [PATCH 18/64] photo frame customization --- app/assets/stylesheets/funs.css.scss | 88 +-------------- .../stylesheets/inc/_photo_frames.css.scss | 106 ++++++++++++++++++ app/views/notifications/index.html.slim | 9 +- 3 files changed, 115 insertions(+), 88 deletions(-) create mode 100644 app/assets/stylesheets/inc/_photo_frames.css.scss diff --git a/app/assets/stylesheets/funs.css.scss b/app/assets/stylesheets/funs.css.scss index e3df09e..51f96db 100644 --- a/app/assets/stylesheets/funs.css.scss +++ b/app/assets/stylesheets/funs.css.scss @@ -10,6 +10,7 @@ @import 'inc/_tooltips.css.scss'; @import 'inc/_modals.css.scss'; @import 'inc/_tagit.css.scss'; +@import 'inc/photo_frames.css.scss'; html, body { font-family: $baseFontFamily; @@ -887,93 +888,6 @@ html, body { } } -.photo_frame { - @include inline-block; - position: relative; - height: 70px; - width: 70px; - .photo_box { - border: 5px solid #5b5985; - display: block; - &, img { - height: 60px; - width: 60px; - border-radius: 50%; - } - } - .arrow { - border: { - top: 8px solid transparent; - left: 8px solid #5b5985; - bottom: 8px solid transparent; - } - position: absolute; - right: -5px; - top: 50%; - margin-top: -8px; - } - .circle_content_obj { - background: #5b5985; - border: 1px solid #363453; - height: 28px; - width: 28px; - position: absolute; - border-radius: 50%; - right: 0; - bottom: -5px; - > div { - height: 16px; - width: 16px; - margin: 6px 0 0 6px; - } - .image { - background: asset_url("content-obj-icons.png", image) no-repeat left -42px; - } - .video { - background: asset_url("content-obj-icons.png", image) no-repeat -21px -42px; - } - .post { - background: asset_url("content-obj-icons.png", image) no-repeat -42px -42px; - } - &:hover{cursor: default;} - } - .circle_follow_status { - position: absolute; - left: -15px; - top: 50%; - margin-top: -15px; - line-height: 24px; - text-align: center; - a { - display: block; - height: 32px; - width: 32px; - background: { - image: asset_url("follow-icons.png", image); - repeat: no-repeat; - } - &.follow { - background-position: -35px -35px; - &:hover { - background-position: -35px 0; - } - } - &.unfollow { - background-position: -70px -105px; - &:hover { - background-position: -70px -70px; - } - } - &.settings { - background-position: -106px 0; - } - } - } - &:hover { - cursor: pointer; - } -} - .tabs_box { .nav_tabs { li { diff --git a/app/assets/stylesheets/inc/_photo_frames.css.scss b/app/assets/stylesheets/inc/_photo_frames.css.scss new file mode 100644 index 0000000..d27d81b --- /dev/null +++ b/app/assets/stylesheets/inc/_photo_frames.css.scss @@ -0,0 +1,106 @@ +.photo_frame { + @include inline-block; + position: relative; + height: 70px; + width: 70px; + .photo_box { + border: 5px solid #5b5985; + display: block; + &, img { + height: 60px; + width: 60px; + border-radius: 50%; + } + } + .arrow { + border: { + top: 8px solid transparent; + left: 8px solid #5b5985; + bottom: 8px solid transparent; + } + position: absolute; + right: -5px; + top: 50%; + margin-top: -8px; + } + .circle_content_obj { + background: #5b5985; + border: 1px solid #363453; + height: 28px; + width: 28px; + position: absolute; + border-radius: 50%; + right: 0; + bottom: -5px; + > div { + height: 16px; + width: 16px; + margin: 6px 0 0 6px; + } + .image { + background: asset_url("content-obj-icons.png", image) no-repeat left -42px; + } + .video { + background: asset_url("content-obj-icons.png", image) no-repeat -21px -42px; + } + .post { + background: asset_url("content-obj-icons.png", image) no-repeat -42px -42px; + } + &:hover{cursor: default;} + } + .circle_follow_status { + position: absolute; + left: -15px; + top: 50%; + margin-top: -15px; + line-height: 24px; + text-align: center; + a { + display: block; + height: 32px; + width: 32px; + background: { + image: asset_url("follow-icons.png", image); + repeat: no-repeat; + } + &.follow { + background-position: -35px -35px; + &:hover { + background-position: -35px 0; + } + } + &.unfollow { + background-position: -70px -105px; + &:hover { + background-position: -70px -70px; + } + } + &.settings { + background-position: -106px 0; + } + } + } + &:hover { + cursor: pointer; + } + + &.photo_frame_shadow{ + .photo_box { + @include box-shadow(0 1px 3px rgba(91, 89, 133, .25), inset 0 0 8px rgba(0, 0, 0, .15)); + } + } + + &.photo_frame_sm { + width: 36px; + height: 36px; + .photo_box { + border: solid 3px #5b5985; + height: 30px; + width: 30px; + img { + height: 30px; + width: 30px; + } + } + } +} \ No newline at end of file diff --git a/app/views/notifications/index.html.slim b/app/views/notifications/index.html.slim index 276b9e4..f8937ff 100644 --- a/app/views/notifications/index.html.slim +++ b/app/views/notifications/index.html.slim @@ -5,4 +5,11 @@ .rating_layout ul - @notifications.each do |n| - li #{link_to(n.user.login, n.user)} #{n.action} #{n.subject.class.name} #{link_to n.target.class.name, n.target if n.target} #{n.created_at} \ No newline at end of file + li + .photo_frame + = link_to show_avatar(n.user), n.user, class: 'photo_box' + = link_to n.user.login, n.user + = n.action + = n.subject.class.name + = link_to n.target.class.name, n.target if n.target + = n.created_at \ No newline at end of file From 204d1b3b96f228b2731495bf14b4e16216e74ad6 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Wed, 16 Apr 2014 10:45:07 +0300 Subject: [PATCH 19/64] comments without design --- Gemfile | 2 + Gemfile.lock | 7 +++ app/assets/javascripts/comments.js.coffee | 52 +++++++++++++++++ app/controllers/comments_controller.rb | 58 +++++++++++++++++++ app/controllers/funs_controller.rb | 3 + app/helpers/funs_helper.rb | 9 +++ app/models/comment.rb | 42 ++++++++++++++ app/models/fun.rb | 1 + app/views/comments/_comment.html.slim | 22 +++++++ app/views/comments/_list.html.slim | 11 ++++ app/views/funs/show.html.slim | 1 + config/routes.rb | 5 ++ ...as_commentable_with_threading_migration.rb | 21 +++++++ ...0416070220_add_cached_votes_to_comments.rb | 19 ++++++ db/schema.rb | 25 +++++++- lib/awesome_nested_tree.rb | 27 +++++++++ 16 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/comments.js.coffee create mode 100644 app/controllers/comments_controller.rb create mode 100644 app/models/comment.rb create mode 100644 app/views/comments/_comment.html.slim create mode 100644 app/views/comments/_list.html.slim create mode 100644 db/migrate/20140415144524_acts_as_commentable_with_threading_migration.rb create mode 100644 db/migrate/20140416070220_add_cached_votes_to_comments.rb create mode 100644 lib/awesome_nested_tree.rb diff --git a/Gemfile b/Gemfile index 1149488..3cf760c 100644 --- a/Gemfile +++ b/Gemfile @@ -112,6 +112,8 @@ gem 'jquery-fileupload-rails' gem 'jquery-rails' gem 'jquery-ui-rails' +gem 'acts_as_commentable_with_threading' + # To use ActiveModel has_secure_password # gem 'bcrypt-ruby', '~> 3.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index 4e2e86c..3d28228 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -30,9 +30,15 @@ GEM multi_json (~> 1.0) acts-as-taggable-on (2.4.1) rails (>= 3, < 5) + acts_as_commentable_with_threading (1.2.0) + activerecord (>= 3.0) + activesupport (>= 3.0) + awesome_nested_set (>= 2.0) acts_as_votable (0.5.0) rails (>= 3.0.0) arel (3.0.2) + awesome_nested_set (2.1.6) + activerecord (>= 3.0.0) bcrypt-ruby (3.0.1) better_errors (0.9.0) coderay (>= 1.0.0) @@ -261,6 +267,7 @@ PLATFORMS DEPENDENCIES acts-as-taggable-on + acts_as_commentable_with_threading acts_as_votable (~> 0.5.0) better_errors binding_of_caller diff --git a/app/assets/javascripts/comments.js.coffee b/app/assets/javascripts/comments.js.coffee new file mode 100644 index 0000000..293634e --- /dev/null +++ b/app/assets/javascripts/comments.js.coffee @@ -0,0 +1,52 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ + + +jQuery -> + # Create a comment + $list = $('.comment-list') + $form = $list.find('.new_comment') + .on 'ajax:beforeSend', (e, xhr, settings) -> + $(this).find('textarea').addClass('uneditable-input').attr('disabled', 'disabled') + .on 'ajax:success', (e, response, status, xhr) -> + $this = $(this) + $this.find('textarea').removeClass('uneditable-input').removeAttr('disabled', 'disabled').val(''); + + if xhr.getResponseHeader('Content-Type').indexOf('javascript') == -1 + $(response).hide().appendTo($this.prev()).show('slow') + + $list + .on 'ajax:beforeSend', '.close', -> + $(this).closest('.comment').fadeTo('fast', 0.5) + .on 'ajax:success', '.close', -> + $(this).closest('.comment').hide('fast') + .on 'ajax:error', '.close', -> + $(this).closest('.comment').fadeTo('fast', 1) + + .on 'click', '.comment_for', (e) -> + e.preventDefault() + $this = $(this) + return false unless $form.length + $form.next(':hidden').show() + $this.hide().before($form) + $form.find('input[name*=parent_id]').val($this.data('id') || '') + + .on 'ajax:before', '.voting', -> + $this = $(this) + return false if $this.data('sending') + $this.data('sending', true) + + .on 'ajax:success', '.voting', (e, response) -> + $this = $(this) + $this.find('.count-likes').val(response.like) + $this.find('.count-dislikes').val(response.dislike) + $this.find('.btn').removeClass('disabled').data('method', false) + + if response.vote + $this.find('.btn').first().addClass('disabled').data('method', 'delete') + else if response.vote == false + $this.find('.btn').last().addClass('disabled').data('method', 'delete') + + .on 'ajax:complete', '.voting', -> + $(this).data('sending', false) diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb new file mode 100644 index 0000000..8d3d091 --- /dev/null +++ b/app/controllers/comments_controller.rb @@ -0,0 +1,58 @@ +class CommentsController < ApplicationController + before_filter :load_obj_and_build_comment, only: :create + load_resource except: :create + authorize_resource + + def create + if @comment.save + + unless params[:comment][:parent_id].blank? + parent = @obj.comment_threads.find_by(id: params[:comment][:parent_id]) + + @comment.move_to_child_of parent if parent + end + + render partial: 'comments/comment', locals: { comment: @comment }, + layout: false, status: :created + else + render js: "alert('error saving');" + end + end + + def destroy + if @comment.destroy + render json: @comment, status: :ok + else + render js: "alert('error deleting comment');" + end + end + + def vote + vote = params[:type] != 'dislike' + if current_user.voted_as_when_voted_for(@comment) != vote + @comment.vote voter: current_user, vote: vote + end + render json: likes_data + end + + def unvote + @comment.unliked_by current_user + render json: likes_data + end + + private + + def load_obj_and_build_comment + data = params[:comment] + @obj = Comment.find_commentable(data[:commentable_type], data[:commentable_id]) + @comment = Comment.build_from(@obj, current_user.id, data[:body]) + end + + def likes_data + { + like: @comment.count_votes_up, + dislike: @comment.cached_votes_down, + vote: current_user.voted_as_when_voted_for(@comment) + } + end +end diff --git a/app/controllers/funs_controller.rb b/app/controllers/funs_controller.rb index b6deeb5..5d8fd0a 100644 --- a/app/controllers/funs_controller.rb +++ b/app/controllers/funs_controller.rb @@ -34,6 +34,9 @@ def feed # GET /funs/1 def show + @tree = AwesomeNestedTree.new @fun.comment_threads.includes(:user) + @new_comment = Comment.build_from(@fun) + @funs = @fun.get_month_trends(current_user, cookies_store[:type]).includes(:user, :content).limit 9 respond_to :html, :js end diff --git a/app/helpers/funs_helper.rb b/app/helpers/funs_helper.rb index 8dbd04e..727b238 100644 --- a/app/helpers/funs_helper.rb +++ b/app/helpers/funs_helper.rb @@ -220,4 +220,13 @@ def link_to_fun_title(fun) end end + def vote_link(text, url, voted) + options = { class: [:btn], remote: true } + if voted + options[:class] << :disabled + options[:method] = :delete + end + link_to text, url, options + end + end \ No newline at end of file diff --git a/app/models/comment.rb b/app/models/comment.rb new file mode 100644 index 0000000..cb92951 --- /dev/null +++ b/app/models/comment.rb @@ -0,0 +1,42 @@ +class Comment < ActiveRecord::Base + attr_accessible :commentable, :body, :user_id + acts_as_nested_set scope: [:commentable_id, :commentable_type] + + validates :body, :user, presence: true + + # NOTE: install the acts_as_votable plugin if you + # want user to vote on the quality of comments. + acts_as_votable + + belongs_to :commentable, polymorphic: true + + # NOTE: Comments belong to a user + belongs_to :user + + # Helper class method to lookup all comments assigned + # to all commentable types for a given user. + scope :find_comments_by_user, lambda { |user| + where(user_id: user.id).order('created_at DESC') + } + + # Helper class method to look up all comments for + # commentable class name and commentable id. + scope :find_comments_for_commentable, lambda { |commentable_str, commentable_id| + where(commentable_type: commentable_str.to_s, commentable_id: commentable_id).order('created_at DESC') + } + + class << self + # Helper class method that allows you to build a comment + # by passing a commentable object, a user_id, and comment text + # example in readme + def build_from(obj, user_id = nil, comment = '') + new commentable: obj, body: comment, user_id: user_id + end + + # Helper class method to look up a commentable object + # given the commentable class name and id + def find_commentable(commentable_str, commentable_id) + commentable_str.constantize.find(commentable_id) + end + end +end diff --git a/app/models/fun.rb b/app/models/fun.rb index e54733e..e00e823 100644 --- a/app/models/fun.rb +++ b/app/models/fun.rb @@ -29,6 +29,7 @@ class Fun < ActiveRecord::Base # Initialize "acts_as_votable" gem for "likes" acts_as_votable + acts_as_commentable def attributes=(attributes = {}) self.content_type = attributes[:content_type] diff --git a/app/views/comments/_comment.html.slim b/app/views/comments/_comment.html.slim new file mode 100644 index 0000000..1ca81a6 --- /dev/null +++ b/app/views/comments/_comment.html.slim @@ -0,0 +1,22 @@ +.comment + - if can? :destroy, Comment + = link_to '×', comment_path(comment), method: :delete, remote: true, confirm: 'Are you sure you want to remove this comment?', disable_with: '×', class: 'close' + span.muted= l comment.created_at + strong= comment.user.login + + - vote = current_user ? current_user.voted_as_when_voted_for(comment) : nil + .input-prepend.input-append.voting + = vote_link '+', vote_comment_path(comment), vote + input.span1.text-center.text-success.count-likes disabled=true value=comment.count_votes_up type=:text + input.span1.text-center.text-error.count-dislikes disabled=true value=comment.count_votes_down type=:text + = vote_link '-', vote_comment_path(comment, :dislike), vote === false + + div= comment.body + + blockquote + - unless comment.leaf? + = render partial: 'comments/comment', collection: tree.children(comment.id), as: :comment, locals: { tree: tree } + - if can? :create, Comment + = link_to 'answer', 'javascript:;', class: 'comment_for', data: { id: comment.id } + + hr \ No newline at end of file diff --git a/app/views/comments/_list.html.slim b/app/views/comments/_list.html.slim new file mode 100644 index 0000000..9d77433 --- /dev/null +++ b/app/views/comments/_list.html.slim @@ -0,0 +1,11 @@ +.comment-list + = render partial: 'comments/comment', collection: tree.root, as: :comment, locals: { tree: tree } + - if can? :create, Comment + = form_for new_comment, remote: true do |f| + = f.text_area :body, rows: 3, class: 'input-block-level' + = f.hidden_field :parent_id + = f.hidden_field :commentable_id + = f.hidden_field :commentable_type + = f.button :submit, class: 'btn btn-primary', disable_with: 'Submitting…' + + = link_to 'Add comment', 'javascript:;', class: 'comment_for', style: 'display:none' \ No newline at end of file diff --git a/app/views/funs/show.html.slim b/app/views/funs/show.html.slim index ada5406..c9dce9b 100644 --- a/app/views/funs/show.html.slim +++ b/app/views/funs/show.html.slim @@ -36,6 +36,7 @@ .tags = show_cached_tags @fun a[name='comments'] + = render partial: 'comments/list', locals: { new_comment: @new_comment, tree: @tree } .comments_block#vk_comments javascript: VK.Widgets.Like("vk_like", {type: "mini", height: 20, pageTitle: "#{@fun.content.title}", pageUrl: "#{fun_url(@fun)}", pageImage: "#{fun_image_url(@fun, :small)}"}); diff --git a/config/routes.rb b/config/routes.rb index 402b8ef..371fe12 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,6 +2,11 @@ root to: 'funs#index' + resources :comments, only: [:create, :destroy] do + get 'vote(/:type)', action: :vote, on: :member, as: :vote + delete 'vote(/:type)', action: :unvote, on: :member + end + resources :notifications, only: :index get 'reports', to: 'reports#index' diff --git a/db/migrate/20140415144524_acts_as_commentable_with_threading_migration.rb b/db/migrate/20140415144524_acts_as_commentable_with_threading_migration.rb new file mode 100644 index 0000000..b8fbb9d --- /dev/null +++ b/db/migrate/20140415144524_acts_as_commentable_with_threading_migration.rb @@ -0,0 +1,21 @@ +class ActsAsCommentableWithThreadingMigration < ActiveRecord::Migration + def self.up + create_table :comments, force: true do |t| + t.integer :commentable_id, default: 0 + t.string :commentable_type + t.string :title + t.text :body + t.string :subject + t.integer :user_id, default: 0, null: false + t.integer :parent_id, :lft, :rgt + t.timestamps + end + + add_index :comments, :user_id + add_index :comments, [:commentable_id, :commentable_type] + end + + def self.down + drop_table :comments + end +end diff --git a/db/migrate/20140416070220_add_cached_votes_to_comments.rb b/db/migrate/20140416070220_add_cached_votes_to_comments.rb new file mode 100644 index 0000000..7bfffd3 --- /dev/null +++ b/db/migrate/20140416070220_add_cached_votes_to_comments.rb @@ -0,0 +1,19 @@ +class AddCachedVotesToComments < ActiveRecord::Migration + def self.up + add_column :comments, :cached_votes_score, :integer, default: 0 + add_column :comments, :cached_votes_up, :integer, default: 0 + add_column :comments, :cached_votes_down, :integer, default: 0 + add_index :comments, :cached_votes_score + add_index :comments, :cached_votes_up + add_index :comments, :cached_votes_down + + # Uncomment this line to force caching of existing votes + Comment.find_each(&:update_cached_votes) + end + + def self.down + remove_column :comments, :cached_votes_score + remove_column :comments, :cached_votes_up + remove_column :comments, :cached_votes_down + end +end diff --git a/db/schema.rb b/db/schema.rb index a83a27a..ea1ca0b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,30 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20140411085401) do +ActiveRecord::Schema.define(:version => 20140416070220) do + + create_table "comments", :force => true do |t| + t.integer "commentable_id", :default => 0 + t.string "commentable_type" + t.string "title" + t.text "body" + t.string "subject" + t.integer "user_id", :default => 0, :null => false + t.integer "parent_id" + t.integer "lft" + t.integer "rgt" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "cached_votes_score", :default => 0 + t.integer "cached_votes_up", :default => 0 + t.integer "cached_votes_down", :default => 0 + end + + add_index "comments", ["cached_votes_down"], :name => "index_comments_on_cached_votes_down" + add_index "comments", ["cached_votes_score"], :name => "index_comments_on_cached_votes_score" + add_index "comments", ["cached_votes_up"], :name => "index_comments_on_cached_votes_up" + add_index "comments", ["commentable_id", "commentable_type"], :name => "index_comments_on_commentable_id_and_commentable_type" + add_index "comments", ["user_id"], :name => "index_comments_on_user_id" create_table "funs", :force => true do |t| t.integer "user_id" diff --git a/lib/awesome_nested_tree.rb b/lib/awesome_nested_tree.rb new file mode 100644 index 0000000..054b29b --- /dev/null +++ b/lib/awesome_nested_tree.rb @@ -0,0 +1,27 @@ +class AwesomeNestedTree + + attr_reader :all, :root + + def initialize(all) + @all = all + @root = [] + @children = {} + + @all.map do |item| + if item.parent_id + @children[item.parent_id] ||= [] + @children[item.parent_id] << item + else + @root << item + end + end + end + + def children?(id) + @children.key? id + end + + def children(id) + @children[id] + end +end \ No newline at end of file From 1c86d3c2414b68effe46fbcbf2779a6c5c397a68 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Wed, 16 Apr 2014 11:45:07 +0300 Subject: [PATCH 20/64] answer to comment --- app/controllers/comments_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 8d3d091..a4b85e6 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -7,7 +7,7 @@ def create if @comment.save unless params[:comment][:parent_id].blank? - parent = @obj.comment_threads.find_by(id: params[:comment][:parent_id]) + parent = @obj.comment_threads.find(params[:comment][:parent_id]) rescue nil @comment.move_to_child_of parent if parent end From c4bbc03e57eece91d76ec4cf0ffa52f27e87937f Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Wed, 16 Apr 2014 11:45:47 +0300 Subject: [PATCH 21/64] comment rights --- app/models/ability.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/ability.rb b/app/models/ability.rb index 0f289c1..0bf76cb 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -18,6 +18,8 @@ def initialize(user) can :update, User, id: user.id can :create, Report can :read, :all + can :create, Comment + can :destroy, Comment, user_id: user.id, leaf?: true cannot [:destroy, :read], Report cannot :show, Notification else From f3fc8a6d5fa0a19a22f11fb70fe76b2bb6610648 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Wed, 16 Apr 2014 12:54:14 +0300 Subject: [PATCH 22/64] cache commentable comments count --- app/models/comment.rb | 9 +++++++++ app/models/fun.rb | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/models/comment.rb b/app/models/comment.rb index cb92951..fb76a53 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -1,4 +1,7 @@ class Comment < ActiveRecord::Base + after_create :update_commentable_counter + after_destroy :update_commentable_counter + attr_accessible :commentable, :body, :user_id acts_as_nested_set scope: [:commentable_id, :commentable_type] @@ -39,4 +42,10 @@ def find_commentable(commentable_str, commentable_id) commentable_str.constantize.find(commentable_id) end end + + private + + def update_commentable_counter + commentable.update_comments_count if commentable.respond_to? :update_comments_count + end end diff --git a/app/models/fun.rb b/app/models/fun.rb index e00e823..b208557 100644 --- a/app/models/fun.rb +++ b/app/models/fun.rb @@ -1,5 +1,5 @@ class Fun < ActiveRecord::Base - attr_accessible :content_attributes, :content_type, :comments_count + attr_accessible :content_attributes, :content_type attr_accessible :content_id, :content_type, :user_id, :owner_id, as: :admin after_destroy :delete_content before_destroy :delete_likes @@ -221,6 +221,10 @@ def delete_content content.destroy unless repost? end + def update_comments_count + update_attribute :comments_counter, comment_threads.count + end + private def create_notification From a0c56e21ef5c60f1673b3b0ef7b448d726b846e3 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Wed, 16 Apr 2014 12:54:35 +0300 Subject: [PATCH 23/64] remove vk comments --- app/controllers/socials_controller.rb | 18 ------------------ app/views/funs/show.html.slim | 11 ++++------- 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/app/controllers/socials_controller.rb b/app/controllers/socials_controller.rb index be8efd2..8710944 100644 --- a/app/controllers/socials_controller.rb +++ b/app/controllers/socials_controller.rb @@ -1,26 +1,8 @@ class SocialsController < ApplicationController before_filter :only_xhr_request - def vkontakte_comments - if check_sign params - @fun = Fun.find(params[:id]) - @fun.update_attribute :comments_counter, params[:num] - head :ok - else - head :bad_request - end - end - def social_likes @fun = Fun.find(params[:id]) render layout: false end - - private - - def check_sign(params) - checkstr = Settings.widgets.vkontakte.comments.secret.to_s + params[:date].to_s + params[:num].to_s + params[:last_comment].to_s - params[:sign].to_s == Digest::MD5.hexdigest(checkstr.encode('windows-1251')) - end - end \ No newline at end of file diff --git a/app/views/funs/show.html.slim b/app/views/funs/show.html.slim index c9dce9b..4817103 100644 --- a/app/views/funs/show.html.slim +++ b/app/views/funs/show.html.slim @@ -23,6 +23,8 @@ #vk_like .fb-like[data-href="#{fun_url(@fun)}" data-send="false" data-layout="button_count" data-width="450" data-show-faces="true" data-font="arial"] a[href="https://twitter.com/share" rel="nofollow" class="twitter-share-button" data-via="bitfun" data-lang="ru" data-related="butfun" data-text="#{@fun.content.title || t('meta_tags.main.title')}"] Tweet + javascript: + VK.Widgets.Like("vk_like", {type: "mini", height: 20, pageTitle: "#{@fun.content.title}", pageUrl: "#{fun_url(@fun)}", pageImage: "#{fun_image_url(@fun, :small)}"}); .follow_parent = follow_link(@fun.user) = edit_fun_link @fun @@ -36,13 +38,8 @@ .tags = show_cached_tags @fun a[name='comments'] - = render partial: 'comments/list', locals: { new_comment: @new_comment, tree: @tree } - .comments_block#vk_comments - javascript: - VK.Widgets.Like("vk_like", {type: "mini", height: 20, pageTitle: "#{@fun.content.title}", pageUrl: "#{fun_url(@fun)}", pageImage: "#{fun_image_url(@fun, :small)}"}); - VK.Widgets.Comments("vk_comments", { limit: 15, width: "670", attach: "*", onChange: function(num, last_comment, date, sign){ - $.post( "#{vk_comments_callback_path(@fun.id)}", { num: num.toString(), last_comment:last_comment , date: date, sign:sign } ); - } }, #{@fun.id}); + .comments_block + = render partial: 'comments/list', locals: { new_comment: @new_comment, tree: @tree } .aside.sidebar section.vertical_carousel From ee2c9332a1acb6b7f536387b86ce3dbaa7cde9c8 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Thu, 17 Apr 2014 09:45:05 +0300 Subject: [PATCH 24/64] comments design --- app/assets/images/chat.png | Bin 0 -> 375 bytes app/assets/stylesheets/funs.css.scss | 105 ++++++++++++++++++- app/assets/stylesheets/inc/_helpers.css.scss | 9 +- app/helpers/funs_helper.rb | 8 +- app/views/comments/_comment.html.slim | 42 ++++---- app/views/comments/_list.html.slim | 27 +++-- 6 files changed, 156 insertions(+), 35 deletions(-) create mode 100644 app/assets/images/chat.png diff --git a/app/assets/images/chat.png b/app/assets/images/chat.png new file mode 100644 index 0000000000000000000000000000000000000000..8558b64a25237da137835508138f9f87ddbfb7ba GIT binary patch literal 375 zcmeAS@N?(olHy`uVBq!ia0vp^f*>{r8<6y`Y?T61Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmPqivW+NfZ(J6Zw3ZN7Ec$)5RLOwFBy6<2MQefcz>M| zrv^vXVvbv#OV_doNORA=-qC);_V_zhpUqVa&Rf2+U7Hl4p>#t-MbOl2wpv>FXZ`zU zYK%Xh?ervXG=U_{a$fEs84&@p6*X;GL#Y)F1pMx zUE*Pm(zmv5iFQ+_3kMu0wK2{+ru{(7byC~ Date: Thu, 17 Apr 2014 09:45:46 +0300 Subject: [PATCH 25/64] fix scss style --- app/assets/stylesheets/funs.css.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/funs.css.scss b/app/assets/stylesheets/funs.css.scss index 1def670..1a53d15 100644 --- a/app/assets/stylesheets/funs.css.scss +++ b/app/assets/stylesheets/funs.css.scss @@ -1292,7 +1292,7 @@ html, body { .like_box, .repost_box, .complain_box { padding: 0 1px; margin-right: 0; } .item_adds { - background: url(/assets/post-navbar-bg.png) repeat-x 0 -50px; + background: asset_url("post-navbar-bg.png", image) repeat-x 0 -50px; padding-bottom: 0; float: left; overflow: hidden; From b0893d4de06cedd14aaaa272b866f29d4655a133 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Thu, 17 Apr 2014 09:54:03 +0300 Subject: [PATCH 26/64] user cannot destroy own comment --- app/models/ability.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index 0bf76cb..8b9d5ca 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -19,7 +19,6 @@ def initialize(user) can :create, Report can :read, :all can :create, Comment - can :destroy, Comment, user_id: user.id, leaf?: true cannot [:destroy, :read], Report cannot :show, Notification else From ee734a86798d36867f2b51a7ba4b0406e50028c2 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Thu, 17 Apr 2014 10:13:59 +0300 Subject: [PATCH 27/64] comment remove btn --- app/assets/stylesheets/funs.css.scss | 23 ++++++++++++++++++++++- app/views/comments/_comment.html.slim | 4 ++-- app/views/comments/_list.html.slim | 2 +- config/locales/ru.yml | 6 +++--- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/app/assets/stylesheets/funs.css.scss b/app/assets/stylesheets/funs.css.scss index 1a53d15..ba2c9be 100644 --- a/app/assets/stylesheets/funs.css.scss +++ b/app/assets/stylesheets/funs.css.scss @@ -22,6 +22,16 @@ html, body { @include btn-orange(35px); } +.btn-close-sm { + background: asset_url('btn-fun-icons.png', image) no-repeat -22px 0; + height: 21px; + width: 21px; + &:hover { + background-position: 0 0; + cursor: pointer; + } +} + .page { margin: $page_margin_top auto 0; width: $page_width; @@ -2339,7 +2349,7 @@ and (orientation:landscape) { .info_list{ color: #474747; font-size: 13px; - .list_title{ + .info_list_title{ color: #000000; font: { weight: bold; @@ -2354,6 +2364,7 @@ and (orientation:landscape) { border-top: 1px solid #e2e2e2; padding-top: 20px; margin-top: 20px; + position: relative; .info_body{ margin-left: 90px; } @@ -2382,6 +2393,16 @@ and (orientation:landscape) { } &:hover{ text-decoration: underline; } } + .btn-close-sm { + display: none; + position: absolute; + top: -10px; + right: -10px; + z-index: 1001; + } + &:hover { + > .btn-close-sm { display: block} + } } } diff --git a/app/views/comments/_comment.html.slim b/app/views/comments/_comment.html.slim index 36f30ad..e5918a8 100644 --- a/app/views/comments/_comment.html.slim +++ b/app/views/comments/_comment.html.slim @@ -1,6 +1,6 @@ .comment.info_element - /- if can? :destroy, Comment - / = link_to '×', comment_path(comment), method: :delete, remote: true, confirm: 'Are you sure you want to remove this comment?', disable_with: '×', class: 'close' + - if can? :destroy, Comment + = link_to '', comment_path(comment), method: :delete, remote: true, confirm: t('comment.confirm.delete'), class: 'btn-close-sm' .photo_frame.pull-left = link_to show_avatar(comment.user), comment.user, class: 'photo_box' diff --git a/app/views/comments/_list.html.slim b/app/views/comments/_list.html.slim index b648f44..5459ed9 100644 --- a/app/views/comments/_list.html.slim +++ b/app/views/comments/_list.html.slim @@ -1,5 +1,5 @@ .comment-list.info_list - .list_title + .info_list_title ' Комментарии span.gray | ( diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 12c6486..19c27d0 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -205,6 +205,6 @@ ru: tag_list: 'Введите теги (через запятую)' remote_file_url: 'Вставьте ссылку на изображение' url: 'Вставьте ссылку на видео (youtube или vimeo)' - - - + comment: + confirm: + delete: Вы действительно хотите удалить этот комментарий? \ No newline at end of file From e4f6afd6365cf633df3cbc8a57f447c2596257f7 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Thu, 17 Apr 2014 10:48:20 +0300 Subject: [PATCH 28/64] comments design (end) --- app/assets/stylesheets/funs.css.scss | 46 ++++++++++---------- app/assets/stylesheets/inc/_helpers.css.scss | 3 +- app/views/comments/_comment.html.slim | 7 ++- app/views/comments/_list.html.slim | 5 ++- config/locales/ru.yml | 6 ++- 5 files changed, 35 insertions(+), 32 deletions(-) diff --git a/app/assets/stylesheets/funs.css.scss b/app/assets/stylesheets/funs.css.scss index ba2c9be..8459c9e 100644 --- a/app/assets/stylesheets/funs.css.scss +++ b/app/assets/stylesheets/funs.css.scss @@ -2360,39 +2360,36 @@ and (orientation:landscape) { color: #cacaca; } } + .info_action{ + color: #8e8da9; + display: inline-block; + margin-top: 7px; + &.answer{ + padding-left: 20px; + background: { + image: asset_url('chat.png', image); + repeat: no-repeat; + position: 0 50%; + } + } + &:hover{ text-decoration: underline; } + } + .info_muted{ + color: #aaaaaa; + } .info_element{ border-top: 1px solid #e2e2e2; padding-top: 20px; margin-top: 20px; position: relative; - .info_body{ - margin-left: 90px; - } + .info_body{ margin-left: 90px; } .info_title{ color: #6d6b93; &:hover{ text-decoration: underline; } } - .info_muted{ - color: #aaaaaa; - margin-top: 5px; - } - .info_content{ - margin-top: 15px; - } - .info_action{ - color: #8e8da9; - display: inline-block; - margin-top: 7px; - &.answer{ - padding-left: 20px; - background: { - image: asset_url('chat.png', image); - repeat: no-repeat; - position: 0 50%; - } - } - &:hover{ text-decoration: underline; } - } + .info_muted{ margin-top: 5px; } + .info_content{ margin-top: 15px; } + .info_action{ display: inline-block; margin-top: 7px; } .btn-close-sm { display: none; position: absolute; @@ -2404,6 +2401,7 @@ and (orientation:landscape) { > .btn-close-sm { display: block} } } + } .btn-action{ diff --git a/app/assets/stylesheets/inc/_helpers.css.scss b/app/assets/stylesheets/inc/_helpers.css.scss index 1b05640..b37da6a 100644 --- a/app/assets/stylesheets/inc/_helpers.css.scss +++ b/app/assets/stylesheets/inc/_helpers.css.scss @@ -19,4 +19,5 @@ -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; -} \ No newline at end of file +} +.hidden { display: none; } \ No newline at end of file diff --git a/app/views/comments/_comment.html.slim b/app/views/comments/_comment.html.slim index e5918a8..369f8eb 100644 --- a/app/views/comments/_comment.html.slim +++ b/app/views/comments/_comment.html.slim @@ -18,11 +18,10 @@ ' добавил span.date_block= comment.created_at - .info_content= comment.body + - if can? :create, Comment + = link_to t('comment.button.answer'), 'javascript:;', class: 'comment_for info_action answer', data: { id: comment.id } blockquote.info_list - unless comment.leaf? - = render partial: 'comments/comment', collection: tree.children(comment.id), as: :comment, locals: { tree: tree } - - if can? :create, Comment - = link_to 'answer', 'javascript:;', class: 'comment_for info_action answer', data: { id: comment.id } \ No newline at end of file + = render partial: 'comments/comment', collection: tree.children(comment.id), as: :comment, locals: { tree: tree } \ No newline at end of file diff --git a/app/views/comments/_list.html.slim b/app/views/comments/_list.html.slim index 5459ed9..448b273 100644 --- a/app/views/comments/_list.html.slim +++ b/app/views/comments/_list.html.slim @@ -6,7 +6,7 @@ span.total_comments= tree.all.length | ) = render partial: 'comments/comment', collection: tree.root, as: :comment, locals: { tree: tree } - .info_element + .info_element.form_wrapper.hidden - if can? :create, Comment .photo_frame.pull-left = link_to show_avatar(current_user), current_user, class: 'photo_box' @@ -19,4 +19,5 @@ =link_to :submit, 'javascript:;', class: 'btn-orange' - = link_to 'Add comment', 'javascript:;', class: 'comment_for', style: 'display:none' \ No newline at end of file + = link_to t('comment.button.new'), 'javascript:;', class: 'comment_for info_action answer pull-right' + .clearfix \ No newline at end of file diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 19c27d0..0e0ac29 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -207,4 +207,8 @@ ru: url: 'Вставьте ссылку на видео (youtube или vimeo)' comment: confirm: - delete: Вы действительно хотите удалить этот комментарий? \ No newline at end of file + delete: Вы действительно хотите удалить этот комментарий? + button: + new: Добавить комментарий + create: Сохранить комментарий + answer: Ответить \ No newline at end of file From 1d7d4059b97cf14d29548802c130f8c823bbe92e Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Thu, 17 Apr 2014 15:59:31 +0300 Subject: [PATCH 29/64] comments for not signed user --- app/assets/javascripts/application.js | 14 ++++- app/assets/javascripts/comments.js.coffee | 55 ++++++++++++++------ app/assets/stylesheets/funs.css.scss | 9 +++- app/assets/stylesheets/inc/_helpers.css.scss | 2 +- app/controllers/comments_controller.rb | 3 +- app/helpers/funs_helper.rb | 2 +- app/helpers/users_helper.rb | 18 +++++++ app/views/comments/_comment.html.slim | 3 +- app/views/comments/_list.html.slim | 8 +-- 9 files changed, 83 insertions(+), 31 deletions(-) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 6a69b7c..661308e 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -116,13 +116,23 @@ $(function(){ $.fancybox.close() }); + var showAuthRequire = function(){ + show_notice('Авторизируйтесь или зарегистрируйтесь, чтобы можно было выполнять это действие.', 'error'); + }; + $(document).on('click', 'a[data-auth]', function(e){ e.preventDefault(); - show_notice('Авторизируйтесь или зарегистрируйтесь, чтобы можно было выполнять это действие.', 'error'); + showAuthRequire(); }); + + $.rails.allowAction = function(element){ - if ( ! element.attr('data-confirm')) return true + if ( element.data('auth')){ + showAuthRequire(); + return false; + } + if ( ! element.attr('data-confirm')) return true; show_notice(element.data('confirm'), 'confirm', { buttons: [ diff --git a/app/assets/javascripts/comments.js.coffee b/app/assets/javascripts/comments.js.coffee index 293634e..1862b3b 100644 --- a/app/assets/javascripts/comments.js.coffee +++ b/app/assets/javascripts/comments.js.coffee @@ -5,32 +5,52 @@ jQuery -> # Create a comment - $list = $('.comment-list') - $form = $list.find('.new_comment') + + checkVotingScore = ($voting) -> + if parseInt($voting.find('.vote_result').text()) < 0 + $voting.addClass 'red' + else + $voting.removeClass 'red' + + $list = $ '.comment-list' + + $list.find('.voting').each -> + checkVotingScore $(this) + + $form = $list.find('.form_wrapper') .on 'ajax:beforeSend', (e, xhr, settings) -> - $(this).find('textarea').addClass('uneditable-input').attr('disabled', 'disabled') + $(this).find('textarea').attr('disabled', 'disabled') .on 'ajax:success', (e, response, status, xhr) -> $this = $(this) - $this.find('textarea').removeClass('uneditable-input').removeAttr('disabled', 'disabled').val(''); + $this.find('textarea').removeAttr('disabled', 'disabled').val(''); if xhr.getResponseHeader('Content-Type').indexOf('javascript') == -1 - $(response).hide().appendTo($this.prev()).show('slow') + $form.before($(response).hide()) $list - .on 'ajax:beforeSend', '.close', -> + .on 'ajax:beforeSend', '.btn-close-sm', -> $(this).closest('.comment').fadeTo('fast', 0.5) - .on 'ajax:success', '.close', -> + .on 'ajax:success', '.btn-close-sm', (e, response) -> $(this).closest('.comment').hide('fast') - .on 'ajax:error', '.close', -> + .on 'ajax:error', '.btn-close-sm', -> $(this).closest('.comment').fadeTo('fast', 1) .on 'click', '.comment_for', (e) -> e.preventDefault() $this = $(this) - return false unless $form.length - $form.next(':hidden').show() - $this.hide().before($form) - $form.find('input[name*=parent_id]').val($this.data('id') || '') + return true unless $form.length + $this.addClass('hidden') + + $into = $this.siblings('.info_list').last() + $into = $this.closest('.info_list') unless $into.length + + return true unless $into.length + + $form.addClass('hidden').find('input[name*=parent_id]').val($this.data('id') || '') + $into.append $form + $list.find('.comment_for.hidden').not($this).removeClass('hidden') + + $form.removeClass 'hidden' .on 'ajax:before', '.voting', -> $this = $(this) @@ -39,14 +59,15 @@ jQuery -> .on 'ajax:success', '.voting', (e, response) -> $this = $(this) - $this.find('.count-likes').val(response.like) - $this.find('.count-dislikes').val(response.dislike) - $this.find('.btn').removeClass('disabled').data('method', false) + $this.find('.vote_result').text(parseInt(response.score) || 0) + $this.find('.btn-action').removeClass('orange').data('method', false) + + checkVotingScore $this if response.vote - $this.find('.btn').first().addClass('disabled').data('method', 'delete') + $this.find('.btn-action').first().addClass('orange').data('method', 'delete') else if response.vote == false - $this.find('.btn').last().addClass('disabled').data('method', 'delete') + $this.find('.btn-action').last().addClass('orange').data('method', 'delete') .on 'ajax:complete', '.voting', -> $(this).data('sending', false) diff --git a/app/assets/stylesheets/funs.css.scss b/app/assets/stylesheets/funs.css.scss index 8459c9e..3516fd7 100644 --- a/app/assets/stylesheets/funs.css.scss +++ b/app/assets/stylesheets/funs.css.scss @@ -2401,7 +2401,9 @@ and (orientation:landscape) { > .btn-close-sm { display: block} } } - + .info_list{ + margin-left: -60px; + } } .btn-action{ @@ -2431,7 +2433,10 @@ and (orientation:landscape) { .voting{ color: #5b5985; - font-size: 16px; + font: { + size: 16px; + weight: bold; + } line-height: 30px; position: relative; min-width: 40px; diff --git a/app/assets/stylesheets/inc/_helpers.css.scss b/app/assets/stylesheets/inc/_helpers.css.scss index b37da6a..168fe13 100644 --- a/app/assets/stylesheets/inc/_helpers.css.scss +++ b/app/assets/stylesheets/inc/_helpers.css.scss @@ -20,4 +20,4 @@ -moz-box-sizing: border-box; box-sizing: border-box; } -.hidden { display: none; } \ No newline at end of file +.hidden { display: none !important; } \ No newline at end of file diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index a4b85e6..233470d 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -50,8 +50,7 @@ def load_obj_and_build_comment def likes_data { - like: @comment.count_votes_up, - dislike: @comment.cached_votes_down, + score: @comment.cached_votes_score, vote: current_user.voted_as_when_voted_for(@comment) } end diff --git a/app/helpers/funs_helper.rb b/app/helpers/funs_helper.rb index d26e470..6aef9ff 100644 --- a/app/helpers/funs_helper.rb +++ b/app/helpers/funs_helper.rb @@ -226,7 +226,7 @@ def vote_link(class_name, url, voted) options[:class] << :orange options[:method] = :delete end - link_to '', url, options + auth_link_to '', url, options end end \ No newline at end of file diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index f1f69c9..782f5c2 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -84,4 +84,22 @@ def omniauth_link(resource, provider) end end + def auth_link_to(*args, &block) + if block_given? + name = capture(&block) + options = args.first || {} + html_options = args.second + else + name = args[0] + options = args[1] || {} + html_options = args[2] + end + + unless user_signed_in? + html_options[:data] ||= {} + html_options[:data][:auth] = true + end + + link_to(name, options, html_options) + end end \ No newline at end of file diff --git a/app/views/comments/_comment.html.slim b/app/views/comments/_comment.html.slim index 369f8eb..0504a12 100644 --- a/app/views/comments/_comment.html.slim +++ b/app/views/comments/_comment.html.slim @@ -20,8 +20,7 @@ .info_content= comment.body - - if can? :create, Comment - = link_to t('comment.button.answer'), 'javascript:;', class: 'comment_for info_action answer', data: { id: comment.id } + = auth_link_to t('comment.button.answer'), 'javascript:;', class: 'comment_for info_action answer', data: { id: comment.id } blockquote.info_list - unless comment.leaf? = render partial: 'comments/comment', collection: tree.children(comment.id), as: :comment, locals: { tree: tree } \ No newline at end of file diff --git a/app/views/comments/_list.html.slim b/app/views/comments/_list.html.slim index 448b273..e8e55ee 100644 --- a/app/views/comments/_list.html.slim +++ b/app/views/comments/_list.html.slim @@ -6,8 +6,8 @@ span.total_comments= tree.all.length | ) = render partial: 'comments/comment', collection: tree.root, as: :comment, locals: { tree: tree } - .info_element.form_wrapper.hidden - - if can? :create, Comment + - if can? :create, Comment + .info_element.form_wrapper .photo_frame.pull-left = link_to show_avatar(current_user), current_user, class: 'photo_box' .arrow @@ -17,7 +17,7 @@ = f.input :commentable_id, as: :hidden = f.input :commentable_type, as: :hidden - =link_to :submit, 'javascript:;', class: 'btn-orange' + =link_to t('comment.button.create'), 'javascript:;', class: 'btn-orange', rel: :submit - = link_to t('comment.button.new'), 'javascript:;', class: 'comment_for info_action answer pull-right' + = auth_link_to t('comment.button.new'), 'javascript:;', class: ('comment_for info_action answer pull-right' + (can?(:create, Comment) ? ' hidden' : '')) .clearfix \ No newline at end of file From e47d78d2e56fcff513ac0147e564c9d61cfb0f94 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Thu, 17 Apr 2014 16:01:05 +0300 Subject: [PATCH 30/64] like box for reposted fun --- app/controllers/socials_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/socials_controller.rb b/app/controllers/socials_controller.rb index 8710944..68aec7d 100644 --- a/app/controllers/socials_controller.rb +++ b/app/controllers/socials_controller.rb @@ -2,7 +2,7 @@ class SocialsController < ApplicationController before_filter :only_xhr_request def social_likes - @fun = Fun.find(params[:id]) + @fun = Fun.unscoped.find(params[:id]) render layout: false end end \ No newline at end of file From 4da0b968f0b4abddd8a843160ff995a573ec977b Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Thu, 17 Apr 2014 16:15:02 +0300 Subject: [PATCH 31/64] fix comment unvote --- app/controllers/comments_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 233470d..7836f9f 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -36,7 +36,7 @@ def vote end def unvote - @comment.unliked_by current_user + current_user.unvote_for @comment render json: likes_data end From df90cece86763221e6b4710f2e82e8b751d8b026 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Thu, 17 Apr 2014 17:29:07 +0300 Subject: [PATCH 32/64] comments scroll to showed form --- app/assets/javascripts/comments.js.coffee | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/assets/javascripts/comments.js.coffee b/app/assets/javascripts/comments.js.coffee index 1862b3b..9848c68 100644 --- a/app/assets/javascripts/comments.js.coffee +++ b/app/assets/javascripts/comments.js.coffee @@ -6,6 +6,18 @@ jQuery -> # Create a comment + scrollToElement = ($target) -> + $window = $(window) + wb = $window.scrollTop() + $window.height() + tb = $target.offset().top + $target.outerHeight() + + if tb + 10 > wb + + $('html, body').animate( + scrollTop: tb - $window.height() + 10 + 500 + ); + checkVotingScore = ($voting) -> if parseInt($voting.find('.vote_result').text()) < 0 $voting.addClass 'red' @@ -51,6 +63,7 @@ jQuery -> $list.find('.comment_for.hidden').not($this).removeClass('hidden') $form.removeClass 'hidden' + scrollToElement $form .on 'ajax:before', '.voting', -> $this = $(this) From e4b23a375d91103a70bf9109e008556abd81366a Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Fri, 18 Apr 2014 10:05:23 +0300 Subject: [PATCH 33/64] comment depth --- app/assets/javascripts/comments.js.coffee | 35 +++++++++++-------- app/controllers/comments_controller.rb | 6 ++-- app/models/comment.rb | 6 ++++ app/views/comments/_comment.html.slim | 4 +-- ...as_commentable_with_threading_migration.rb | 2 +- db/schema.rb | 1 + 6 files changed, 34 insertions(+), 20 deletions(-) diff --git a/app/assets/javascripts/comments.js.coffee b/app/assets/javascripts/comments.js.coffee index 9848c68..13ffadb 100644 --- a/app/assets/javascripts/comments.js.coffee +++ b/app/assets/javascripts/comments.js.coffee @@ -4,7 +4,7 @@ jQuery -> - # Create a comment + $list = $ '.comment-list' scrollToElement = ($target) -> $window = $(window) @@ -18,34 +18,41 @@ jQuery -> 500 ); + changeTotal = (diff) -> + $list.find('.total_comments').each -> + $this = $(this) + $this.text(Math.max(0, parseInt($this.text()) + diff)) + checkVotingScore = ($voting) -> if parseInt($voting.find('.vote_result').text()) < 0 $voting.addClass 'red' else $voting.removeClass 'red' - $list = $ '.comment-list' - $list.find('.voting').each -> checkVotingScore $(this) $form = $list.find('.form_wrapper') - .on 'ajax:beforeSend', (e, xhr, settings) -> + .on 'ajax:beforeSend', -> + return false unless $.trim($(this).find('textarea').val()).length + .on 'ajax:beforeSend', -> $(this).find('textarea').attr('disabled', 'disabled') - .on 'ajax:success', (e, response, status, xhr) -> - $this = $(this) - $this.find('textarea').removeAttr('disabled', 'disabled').val(''); - - if xhr.getResponseHeader('Content-Type').indexOf('javascript') == -1 - $form.before($(response).hide()) + .on 'ajax:success', (e, response) -> + $(this).find('textarea').val('') + $(response).hide().insertBefore($form).show 'slow' + changeTotal 1 + .on 'ajax:complete', -> + $(this).find('textarea').removeAttr('disabled'); $list .on 'ajax:beforeSend', '.btn-close-sm', -> - $(this).closest('.comment').fadeTo('fast', 0.5) - .on 'ajax:success', '.btn-close-sm', (e, response) -> - $(this).closest('.comment').hide('fast') + $(this).closest('.comment').fadeTo 'fast', 0.5 + .on 'ajax:success', '.btn-close-sm', -> + $(this).closest('.comment').hide 'fast', -> + changeTotal -1 - $(this).find('.comment').length + $(this).remove() .on 'ajax:error', '.btn-close-sm', -> - $(this).closest('.comment').fadeTo('fast', 1) + $(this).closest('.comment').fadeTo 'fast', 1 .on 'click', '.comment_for', (e) -> e.preventDefault() diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 7836f9f..ee883bd 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -9,13 +9,13 @@ def create unless params[:comment][:parent_id].blank? parent = @obj.comment_threads.find(params[:comment][:parent_id]) rescue nil - @comment.move_to_child_of parent if parent + @comment.move_to_child_of parent if parent && parent.allowed_to_answer? end render partial: 'comments/comment', locals: { comment: @comment }, layout: false, status: :created else - render js: "alert('error saving');" + render nothing: true, status: 400 end end @@ -23,7 +23,7 @@ def destroy if @comment.destroy render json: @comment, status: :ok else - render js: "alert('error deleting comment');" + render nothing: true, status: 400 end end diff --git a/app/models/comment.rb b/app/models/comment.rb index fb76a53..29ecc27 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -5,6 +5,8 @@ class Comment < ActiveRecord::Base attr_accessible :commentable, :body, :user_id acts_as_nested_set scope: [:commentable_id, :commentable_type] + ANSWER_DEPTH = 7 + validates :body, :user, presence: true # NOTE: install the acts_as_votable plugin if you @@ -28,6 +30,10 @@ class Comment < ActiveRecord::Base where(commentable_type: commentable_str.to_s, commentable_id: commentable_id).order('created_at DESC') } + def allowed_to_answer? + depth.to_i < ANSWER_DEPTH + end + class << self # Helper class method that allows you to build a comment # by passing a commentable object, a user_id, and comment text diff --git a/app/views/comments/_comment.html.slim b/app/views/comments/_comment.html.slim index 0504a12..b5514d7 100644 --- a/app/views/comments/_comment.html.slim +++ b/app/views/comments/_comment.html.slim @@ -19,8 +19,8 @@ span.date_block= comment.created_at .info_content= comment.body - - = auth_link_to t('comment.button.answer'), 'javascript:;', class: 'comment_for info_action answer', data: { id: comment.id } + - if comment.allowed_to_answer? + = auth_link_to t('comment.button.answer'), 'javascript:;', class: 'comment_for info_action answer', data: { id: comment.id } blockquote.info_list - unless comment.leaf? = render partial: 'comments/comment', collection: tree.children(comment.id), as: :comment, locals: { tree: tree } \ No newline at end of file diff --git a/db/migrate/20140415144524_acts_as_commentable_with_threading_migration.rb b/db/migrate/20140415144524_acts_as_commentable_with_threading_migration.rb index b8fbb9d..d11c242 100644 --- a/db/migrate/20140415144524_acts_as_commentable_with_threading_migration.rb +++ b/db/migrate/20140415144524_acts_as_commentable_with_threading_migration.rb @@ -7,7 +7,7 @@ def self.up t.text :body t.string :subject t.integer :user_id, default: 0, null: false - t.integer :parent_id, :lft, :rgt + t.integer :parent_id, :lft, :rgt, :depth t.timestamps end diff --git a/db/schema.rb b/db/schema.rb index ea1ca0b..4f2a621 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -23,6 +23,7 @@ t.integer "parent_id" t.integer "lft" t.integer "rgt" + t.integer "depth" t.datetime "created_at", :null => false t.datetime "updated_at", :null => false t.integer "cached_votes_score", :default => 0 From 85ad35ec092748a99beaf0c626f3fe094fd6fe35 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Fri, 18 Apr 2014 16:15:15 +0300 Subject: [PATCH 34/64] time ago script --- Gemfile | 2 + Gemfile.lock | 3 + app/assets/javascripts/date-time-format.js | 100 +++++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 app/assets/javascripts/date-time-format.js diff --git a/Gemfile b/Gemfile index 3cf760c..9229f1b 100644 --- a/Gemfile +++ b/Gemfile @@ -114,6 +114,8 @@ gem 'jquery-ui-rails' gem 'acts_as_commentable_with_threading' +gem 'momentjs-rails' + # To use ActiveModel has_secure_password # gem 'bcrypt-ruby', '~> 3.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index 3d28228..faed5d4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -143,6 +143,8 @@ GEM railties middleware (0.1.0) mime-types (1.23) + momentjs-rails (2.5.1) + railties (>= 3.1) multi_json (1.7.7) multipart-post (1.2.0) mysql2 (0.3.15) @@ -290,6 +292,7 @@ DEPENDENCIES mailcatcher meta-tags meta_request + momentjs-rails mysql2 (>= 0.3.13) omniauth omniauth-facebook diff --git a/app/assets/javascripts/date-time-format.js b/app/assets/javascripts/date-time-format.js new file mode 100644 index 0000000..1bc146e --- /dev/null +++ b/app/assets/javascripts/date-time-format.js @@ -0,0 +1,100 @@ +!function ($, moment) { + + "use strict"; // jshint ;_ + + var settings = { + datetime: false, + refreshMillis: 20000, + todayFormat: '[сегодня в] HH:mm', + yesterdayFormat: '[вчера в] HH:mm', + thisYearFormat: 'D MMM в HH:mm', + defaultFormat: 'D MMM YYYY в HH:mm', + innerSelector: false, + onComplete: false + }; + + var DateTimeFormat = function (element, options) { + options = typeof options == 'object' ? options : {}; + + this.$element = $(element); + this.options = $.extend({}, settings, typeof options == 'object' ? options : {}); + this.dateTimeStr = this.options.datetime || this.$element.data('iso8601'); + + if ( ! (this.dateTimeStr && moment(this.dateTimeStr).isValid())) return; + + this.moment = moment(this.dateTimeStr); + + this.init(); + }; + + DateTimeFormat.prototype = { + + init: function() { + this.setText().startInterval(); + if ($.isFunction(this.options.onComplete)) + this.options.onComplete(this.$element, this) + }, + + setText: function(){ + if (this.options.innerSelector){ + this.$element.find(this.options.innerSelector).text(this.getMomentStr()) + }else{ + this.$element.text(this.getMomentStr()) + } + return this; + }, + + startInterval: function() { + if (this.options.refreshMillis > 0){ + if (this.isLessThenHour()){ + if(!this.intervalId){ + this.intervalId = setInterval($.proxy(this.refreshText, this), this.options.refreshMillis); + } + } + } + return this + }, + + refreshText: function(){ + this.setText(); + + if (this.intervalId && ! this.isLessThenHour()){ + clearInterval(this.intervalId); + } + }, + + getMomentStr: function () { + if (this.isLessThenHour()) return this.moment.fromNow(); + if (this.isToday()) return this.moment.format(this.options.todayFormat); + if (this.isYesterday()) return this.moment.format(this.options.yesterdayFormat); + if (this.isThisYear()) return this.moment.format(this.options.thisYearFormat); + + return this.moment.format(this.options.defaultFormat); + }, + isLessThenHour: function () { + return this.moment.isAfter(moment().subtract(1, 'hour')) + }, + isToday: function () { + return this.moment.isSame(moment(), 'day') + }, + isYesterday: function () { + return this.moment.isSame(moment().subtract(1, 'day'), 'day'); + }, + isThisYear: function () { + return this.moment.isSame(moment(), 'year') + } + }; + + /* DateTimeFormat PLUGIN DEFINITION + * =========================== */ + + $.fn.datetimeformat = function (options) { + return this.each(function () { + var $this = $(this), data = $this.data('datetimeformat'); + if (!data) $this.data('datetimeformat', (new DateTimeFormat(this, options))) + if (typeof options == 'string') data[options]() + }) + }; + + $.fn.datetimeformat.Constructor = DateTimeFormat; +}(window.jQuery, moment); From 012fc5ed98ad9d1b351c685980bd64c512dcdac1 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Fri, 18 Apr 2014 16:15:28 +0300 Subject: [PATCH 35/64] time ago helper --- app/helpers/dates_helper.rb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 app/helpers/dates_helper.rb diff --git a/app/helpers/dates_helper.rb b/app/helpers/dates_helper.rb new file mode 100644 index 0000000..0853754 --- /dev/null +++ b/app/helpers/dates_helper.rb @@ -0,0 +1,5 @@ +module DatesHelper + def time_ago_format(date) + content_tag :span, '', class: 'date_block date-time-format', data: {iso8601: date.to_time.iso8601} + end +end \ No newline at end of file From 496bfc7c40946a926ab14a0e785cb49bcd4f93fa Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Fri, 18 Apr 2014 16:15:55 +0300 Subject: [PATCH 36/64] time ago auto initialize --- app/assets/javascripts/application.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 661308e..a2b50d4 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -11,6 +11,8 @@ //= require source/bootstrap-tab //= require rails.validations //= require hogan.js +//= require moment +//= require moment/ru //= require_tree . $(function(){ @@ -163,6 +165,20 @@ $(function(){ } } }); + + $.fn.findAndFormatDateTime = function(){ + $(this).find('.date-time-format').datetimeformat({ + onComplete: function(element, object){ + element.tooltipster({ + theme: 'tooltips_theme', + offsetY: -5, + content: object.moment.format('YYYY-MM-DD HH:mm') + }); + } + }); + }; + + $(document).findAndFormatDateTime(); }); function show_notice(text, type, options) { From bf40ceab93a59d1bba3260f76ea0ffda438b4cb4 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Fri, 18 Apr 2014 16:16:13 +0300 Subject: [PATCH 37/64] time ago in comments --- app/assets/javascripts/comments.js.coffee | 2 +- app/views/comments/_comment.html.slim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/comments.js.coffee b/app/assets/javascripts/comments.js.coffee index 13ffadb..64e39a5 100644 --- a/app/assets/javascripts/comments.js.coffee +++ b/app/assets/javascripts/comments.js.coffee @@ -39,7 +39,7 @@ jQuery -> $(this).find('textarea').attr('disabled', 'disabled') .on 'ajax:success', (e, response) -> $(this).find('textarea').val('') - $(response).hide().insertBefore($form).show 'slow' + $(response).hide().insertBefore($form).show('slow').findAndFormatDateTime(); changeTotal 1 .on 'ajax:complete', -> $(this).find('textarea').removeAttr('disabled'); diff --git a/app/views/comments/_comment.html.slim b/app/views/comments/_comment.html.slim index b5514d7..d5f7e3a 100644 --- a/app/views/comments/_comment.html.slim +++ b/app/views/comments/_comment.html.slim @@ -16,7 +16,7 @@ = link_to comment.user.login, comment.user.login, class: 'info_title' .info_muted ' добавил - span.date_block= comment.created_at + = time_ago_format comment.created_at .info_content= comment.body - if comment.allowed_to_answer? From def4620695dbe43a5bce806166f754447972cbcf Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Fri, 18 Apr 2014 16:16:35 +0300 Subject: [PATCH 38/64] time ago on show fun page --- app/views/funs/show.html.slim | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/views/funs/show.html.slim b/app/views/funs/show.html.slim index 4817103..73de7e0 100644 --- a/app/views/funs/show.html.slim +++ b/app/views/funs/show.html.slim @@ -11,9 +11,7 @@ .poster = link_to @fun.user.login, @fun.user span добавил • - span.date_block - = time_ago_in_words @fun.created_at - | назад + = time_ago_format @fun.created_at - if @fun.content.title? h1.title = title @fun.content.title From 938364afdccd5e479e16e7ce2ba7fed9d574fcfb Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Fri, 18 Apr 2014 17:50:27 +0300 Subject: [PATCH 39/64] replace time_ago_in_words by js --- app/assets/javascripts/funs/filters.js | 1 + app/assets/javascripts/funs/wall.js | 1 + app/assets/javascripts/users/wall.js | 2 ++ app/views/funs/_box.html.slim | 4 +--- app/views/funs/_list.html.slim | 4 +--- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/funs/filters.js b/app/assets/javascripts/funs/filters.js index 46414f0..e0be964 100644 --- a/app/assets/javascripts/funs/filters.js +++ b/app/assets/javascripts/funs/filters.js @@ -38,6 +38,7 @@ $(function(){ wall.html(data.responseText); wall.initButtonTooltips(); wall.initTooltips(); + wall.findAndFormatDateTime(); $(window).data('endelessscroll').resetFiring(); if (postData.view == 'box'){ diff --git a/app/assets/javascripts/funs/wall.js b/app/assets/javascripts/funs/wall.js index bff0416..7d45b0c 100644 --- a/app/assets/javascripts/funs/wall.js +++ b/app/assets/javascripts/funs/wall.js @@ -111,6 +111,7 @@ $(function(){ $newElems.imagesLoaded(function(){ $newElems.animate({ opacity: 1 }).initButtonTooltips(); $newElems.initTooltips(); + $newElems.findAndFormatDateTime(); if ($wall.data('masonry')) $wall.masonry( 'appended', $newElems, true ); $wall.append($newElems); }); diff --git a/app/assets/javascripts/users/wall.js b/app/assets/javascripts/users/wall.js index b8d6027..c8598a6 100644 --- a/app/assets/javascripts/users/wall.js +++ b/app/assets/javascripts/users/wall.js @@ -31,6 +31,7 @@ $(function(){ wall.html(data.responseText); wall.initButtonTooltips(); wall.initTooltips(); + wall.findAndFormatDateTime(); $(window).data('endelessscroll').resetFiring(); if (currentState == 'box'){ @@ -65,6 +66,7 @@ $(function(){ wall.html(data.responseText); wall.initButtonTooltips(); wall.initTooltips(); + wall.findAndFormatDateTime(); $(window).data('endelessscroll').resetFiring(); if (currentState == 'box'){ if (wall.data('masonry')) wall.masonry('reload'); diff --git a/app/views/funs/_box.html.slim b/app/views/funs/_box.html.slim index 3e96cbd..a7ad6b9 100644 --- a/app/views/funs/_box.html.slim +++ b/app/views/funs/_box.html.slim @@ -12,9 +12,7 @@ article.post_frame.post_card = link_to fun.content.title, fun - else = fun_add_line fun - span.date_block - = time_ago_in_words fun.created_at - | назад + = time_ago_format fun.created_at .post_object .arrow = render_fun_partial fun, :box diff --git a/app/views/funs/_list.html.slim b/app/views/funs/_list.html.slim index 51b2e9c..7a5eab6 100644 --- a/app/views/funs/_list.html.slim +++ b/app/views/funs/_list.html.slim @@ -10,9 +10,7 @@ article.post_frame = link_to fun.user.login, fun.user = fun_add_line(fun, true) || ' добавил ' | • - span.date_block - = time_ago_in_words fun.created_at - | назад + = time_ago_format fun.created_at - if fun.content.title? .title h2 = link_to fun.content.title, fun From c38d1ebebe0cb8064227c4fde1ce063ad4b91655 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 22 Apr 2014 09:31:23 +0300 Subject: [PATCH 40/64] remove notification on fun create --- app/models/fun.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/models/fun.rb b/app/models/fun.rb index b208557..5f31f4f 100644 --- a/app/models/fun.rb +++ b/app/models/fun.rb @@ -4,7 +4,6 @@ class Fun < ActiveRecord::Base after_destroy :delete_content before_destroy :delete_likes before_destroy :delete_reposts - after_create :create_notification # Kaminari pagination config paginates_per 10 @@ -21,7 +20,6 @@ class Fun < ActiveRecord::Base belongs_to :content, polymorphic: true accepts_nested_attributes_for :content, allow_destroy: true has_many :reports, dependent: :destroy - has_many :notifications, as: :subject, dependent: :destroy # Reposts has_many :reposts, class_name: 'Fun', foreign_key: 'parent_id' @@ -224,10 +222,4 @@ def delete_content def update_comments_count update_attribute :comments_counter, comment_threads.count end - - private - - def create_notification - self.notifications.create(user_id: user_id, action: :create) - end end \ No newline at end of file From e4215c1a9ec20c47e5a6dced5fc52122947b565d Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 22 Apr 2014 09:37:52 +0300 Subject: [PATCH 41/64] notification on comment create --- app/models/comment.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/models/comment.rb b/app/models/comment.rb index 29ecc27..7bbe0fe 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -1,6 +1,7 @@ class Comment < ActiveRecord::Base after_create :update_commentable_counter after_destroy :update_commentable_counter + after_create :create_notification attr_accessible :commentable, :body, :user_id acts_as_nested_set scope: [:commentable_id, :commentable_type] @@ -18,6 +19,8 @@ class Comment < ActiveRecord::Base # NOTE: Comments belong to a user belongs_to :user + has_many :notifications, as: :subject, dependent: :destroy + # Helper class method to lookup all comments assigned # to all commentable types for a given user. scope :find_comments_by_user, lambda { |user| @@ -54,4 +57,8 @@ def find_commentable(commentable_str, commentable_id) def update_commentable_counter commentable.update_comments_count if commentable.respond_to? :update_comments_count end + + def create_notification + self.notifications.create(user_id: user_id, action: :create) + end end From 0e8a09dcc91c98a97a2e4a3e6dd60310ef4b9a6e Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 22 Apr 2014 09:44:44 +0300 Subject: [PATCH 42/64] gem meta_request only for development --- Gemfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 9229f1b..347281b 100644 --- a/Gemfile +++ b/Gemfile @@ -63,7 +63,6 @@ gem 'thin' # Show error in better format gem 'better_errors' gem 'binding_of_caller' -gem 'meta_request' # use this gem only for testing VK widgets gem 'localtunnel' @@ -91,6 +90,10 @@ gem 'bourbon' gem 'sass-rails', '~> 3.2.3' +group :development do + gem 'meta_request' +end + group :assets do # Toolkit from Twitter designed to kickstart development of webapps and sites # gem "bootstrap-sass" From f607b33d68214440b31512018f4643ffd48fbb47 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 22 Apr 2014 10:04:55 +0300 Subject: [PATCH 43/64] update gem meta_request and dependencies --- Gemfile.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index faed5d4..375dee5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -98,7 +98,7 @@ GEM chardet (>= 0.9.0) hoe (>= 1.2.0) httpauth (0.2.0) - i18n (0.6.4) + i18n (0.6.9) innertube (1.1.0) joiner (0.2.0) activerecord (>= 3.1.0, < 4.1.0) @@ -112,7 +112,7 @@ GEM jquery-ui-rails (4.0.3) jquery-rails railties (>= 3.1.0) - json (1.8.0) + json (1.8.1) jwt (0.1.8) multi_json (>= 1.5) kaminari (0.14.1) @@ -137,7 +137,7 @@ GEM thin (~> 1.5.0) meta-tags (1.5.0) actionpack - meta_request (0.2.7) + meta_request (0.3.0) callsite rack-contrib railties @@ -145,7 +145,7 @@ GEM mime-types (1.23) momentjs-rails (2.5.1) railties (>= 3.1) - multi_json (1.7.7) + multi_json (1.9.2) multipart-post (1.2.0) mysql2 (0.3.15) net-ssh (2.6.7) @@ -187,7 +187,7 @@ GEM rack (>= 0.9.1) rack-protection (1.5.0) rack - rack-ssl (1.3.3) + rack-ssl (1.3.4) rack rack-test (0.6.2) rack (>= 1.0) @@ -206,7 +206,7 @@ GEM rake (>= 0.8.7) rdoc (~> 3.4) thor (>= 0.14.6, < 2.0) - rake (10.1.0) + rake (10.3.1) rdoc (3.12.2) json (~> 1.4) riddle (1.5.10) @@ -250,7 +250,7 @@ GEM joiner (>= 0.2.0) middleware (>= 0.1.0) riddle (>= 1.5.10) - thor (0.18.1) + thor (0.19.1) tilt (1.4.1) treetop (1.4.14) polyglot From 98a123e2bd291f5eed94af06e504eee63e4db26e Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 22 Apr 2014 11:52:32 +0300 Subject: [PATCH 44/64] change user votes cache --- app/models/user.rb | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 6af4ec5..f5c2d0d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -154,14 +154,20 @@ def reposted?(fun) fun.id.in? reposted_ids end - # Get funs ids which user voted - def voted_ids - @voted_ids ||= votes.where(votable_type: Fun).pluck(:votable_id) + def my_votes + @votes_cache ||= {}.tap do |h| + votes.each do |v| + ts = v.votable_type.to_sym + h[ts] ||= {} + h[ts][v.votable_id] = v.vote_flag + end + end end # Check if user already voted - def voted?(fun) - fun.id.in? voted_ids + def voted?(votable) + ts = votable.class.name.to_sym + my_votes.key?(ts) ? my_votes[ts][votable.id] : nil end # User feeds From 58ce28ca51017e4b4ca7e22bf75f955dda2fb6dc Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 22 Apr 2014 11:53:12 +0300 Subject: [PATCH 45/64] get cached user votes for comments --- app/views/comments/_comment.html.slim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/views/comments/_comment.html.slim b/app/views/comments/_comment.html.slim index d5f7e3a..d785f0f 100644 --- a/app/views/comments/_comment.html.slim +++ b/app/views/comments/_comment.html.slim @@ -7,11 +7,10 @@ .arrow .info_body - - vote = current_user ? current_user.voted_as_when_voted_for(comment) : nil .voting.pull-right - = vote_link :plus, vote_comment_path(comment), vote + = vote_link :plus, vote_comment_path(comment), current_user.voted?(comment) span.vote_result= comment.cached_votes_score - = vote_link :minus, vote_comment_path(comment, :dislike), vote === false + = vote_link :minus, vote_comment_path(comment, :dislike), current_user.voted?(comment) === false = link_to comment.user.login, comment.user.login, class: 'info_title' .info_muted From f84e21263115ab715bdc51f4510b4b991f939309 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 22 Apr 2014 13:01:16 +0300 Subject: [PATCH 46/64] count liked funs on user page --- app/models/user.rb | 4 ++++ app/views/users/show.html.slim | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/user.rb b/app/models/user.rb index f5c2d0d..f502cf4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -164,6 +164,10 @@ def my_votes end end + def votes_count_for(type) + my_votes.key?(type) ? my_votes[type].length : 0 + end + # Check if user already voted def voted?(votable) ts = votable.class.name.to_sym diff --git a/app/views/users/show.html.slim b/app/views/users/show.html.slim index f375aa2..1a6e8d4 100644 --- a/app/views/users/show.html.slim +++ b/app/views/users/show.html.slim @@ -50,7 +50,7 @@ div[class="container feed_layout#{view_partial == 'box' ? ' grid' : ''}"] a.switch.hold_right[href="#{likes_user_path @user}" rel='tooltip' title="#{t('funs.titles.profile.likes')}"] span.toggle_slider span.toggle_name - = t('user.likes', count: @user.voted_ids.count) + = t('user.likes', count: @user.votes_count_for(:Fun)) .tumbler_switch.toggle_view#user_switch_view .toggle_track From 114ed3da23ce25cd87df15d402212b5b94357722 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 22 Apr 2014 14:51:31 +0300 Subject: [PATCH 47/64] user can vote at comments --- app/models/ability.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index 8b9d5ca..c2104fa 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -18,7 +18,7 @@ def initialize(user) can :update, User, id: user.id can :create, Report can :read, :all - can :create, Comment + can [:create, :vote, :unvote], Comment cannot [:destroy, :read], Report cannot :show, Notification else From f67957e8d9636905f287daf20c01f4ceafc91919 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 22 Apr 2014 14:53:29 +0300 Subject: [PATCH 48/64] notification belongs to fun --- app/models/notification.rb | 3 ++- db/migrate/20140411085401_create_notifications.rb | 1 + db/schema.rb | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/models/notification.rb b/app/models/notification.rb index 89d5aa9..a23ad1e 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -1,11 +1,12 @@ class Notification < ActiveRecord::Base attr_accessible :target_id, :target_type, :target, :subject_id, :subject_type, :subject, - :action, :user_id, :receiver_id + :action, :user_id, :receiver_id, :fun belongs_to :subject, polymorphic: true belongs_to :target, polymorphic: true belongs_to :user + belongs_to :fun validates_presence_of :subject_id validates_presence_of :user_id diff --git a/db/migrate/20140411085401_create_notifications.rb b/db/migrate/20140411085401_create_notifications.rb index 8bd35e4..684f238 100644 --- a/db/migrate/20140411085401_create_notifications.rb +++ b/db/migrate/20140411085401_create_notifications.rb @@ -7,6 +7,7 @@ def change t.references :target, polymorphic: true t.integer :user_id t.integer :receiver_id + t.integer :fun_id t.timestamp :created_at end diff --git a/db/schema.rb b/db/schema.rb index 4f2a621..a8145f7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -79,6 +79,7 @@ t.string "target_type" t.integer "user_id" t.integer "receiver_id" + t.integer "fun_id" t.datetime "created_at" end From fc0ee0ed1c19393fb19e47839c1d64ebdf46ce1a Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 22 Apr 2014 15:02:54 +0300 Subject: [PATCH 49/64] save notifications with fun --- app/models/comment.rb | 9 ++++++++- app/models/fun.rb | 4 ++++ lib/acts_as_votable/vote.rb | 11 +++++++---- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/app/models/comment.rb b/app/models/comment.rb index 7bbe0fe..6affbac 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -52,6 +52,10 @@ def find_commentable(commentable_str, commentable_id) end end + def notification_fun + commentable + end + private def update_commentable_counter @@ -59,6 +63,9 @@ def update_commentable_counter end def create_notification - self.notifications.create(user_id: user_id, action: :create) + return if user_id == commentable.user_id + + notifications.create(user_id: user_id, action: :create, + receiver_id: commentable.user_id, fun: commentable ) end end diff --git a/app/models/fun.rb b/app/models/fun.rb index 5f31f4f..7ce5fb7 100644 --- a/app/models/fun.rb +++ b/app/models/fun.rb @@ -129,6 +129,10 @@ def get_month_trends(user, type) Fun.exclude_funs(exclude).where(published_at: month_range).filter_by_type(type).order('cached_votes_total DESC') end + def notification_fun + self + end + class << self def reposters diff --git a/lib/acts_as_votable/vote.rb b/lib/acts_as_votable/vote.rb index 7b33262..bd7f6b7 100644 --- a/lib/acts_as_votable/vote.rb +++ b/lib/acts_as_votable/vote.rb @@ -7,10 +7,13 @@ class Vote < ActiveRecord::Base private def create_notification - notifications.create(user_id: voter_id, action: :create, - receiver_id: votable.user_id, target: votable) - end + return if voter_id == votable.user_id - end + data = { user_id: voter_id, action: :create, receiver_id: votable.user_id } + data[:fun] = votable.notification_fun if votable.respond_to? :notification_fun + data[:target] = votable unless data[:fun] || data[:fun] == votable + notifications.create(data) + end + end end \ No newline at end of file From d5a81c6fcf8461f55978eb253c2bf89fffec0e5e Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 22 Apr 2014 15:32:18 +0300 Subject: [PATCH 50/64] remove unneeded arrow --- app/views/funs/_box.html.slim | 1 - 1 file changed, 1 deletion(-) diff --git a/app/views/funs/_box.html.slim b/app/views/funs/_box.html.slim index a7ad6b9..a75d704 100644 --- a/app/views/funs/_box.html.slim +++ b/app/views/funs/_box.html.slim @@ -14,7 +14,6 @@ article.post_frame.post_card = fun_add_line fun = time_ago_format fun.created_at .post_object - .arrow = render_fun_partial fun, :box .post_nav = small_like_button fun From 79e439e23db69f83837a2220c63ce236c108722e Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 22 Apr 2014 16:02:04 +0300 Subject: [PATCH 51/64] set comment parent before create --- app/controllers/comments_controller.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index ee883bd..3eb189c 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -4,14 +4,13 @@ class CommentsController < ApplicationController authorize_resource def create - if @comment.save - - unless params[:comment][:parent_id].blank? - parent = @obj.comment_threads.find(params[:comment][:parent_id]) rescue nil + unless params[:comment][:parent_id].blank? + parent = @obj.comment_threads.find(params[:comment][:parent_id]) rescue nil - @comment.move_to_child_of parent if parent && parent.allowed_to_answer? - end + @comment.parent = parent if parent && parent.allowed_to_answer? + end + if @comment.save render partial: 'comments/comment', locals: { comment: @comment }, layout: false, status: :created else From a2b3e7d1b6ac08d8a5374c821ea6c0ce921bee21 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 22 Apr 2014 16:11:47 +0300 Subject: [PATCH 52/64] duplicate notification if comment have a parent --- app/models/comment.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/models/comment.rb b/app/models/comment.rb index 6affbac..a15edf8 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -63,9 +63,14 @@ def update_commentable_counter end def create_notification - return if user_id == commentable.user_id + data = { user_id: user_id, action: :create, fun: commentable } - notifications.create(user_id: user_id, action: :create, - receiver_id: commentable.user_id, fun: commentable ) + if user_id != commentable.user_id + notifications.create(data.merge(receiver_id: commentable.user_id)) + end + + if parent && user_id != parent.user_id && commentable.user_id != parent.user_id + notifications.create(data.merge(receiver_id: parent.user_id, target: parent)) + end end end From f461a3e7dbda35aa79e5501b5ec27b51f8a2e35a Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Tue, 22 Apr 2014 16:38:53 +0300 Subject: [PATCH 53/64] fix show user url --- app/views/comments/_comment.html.slim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/comments/_comment.html.slim b/app/views/comments/_comment.html.slim index d785f0f..ea3752f 100644 --- a/app/views/comments/_comment.html.slim +++ b/app/views/comments/_comment.html.slim @@ -12,7 +12,7 @@ span.vote_result= comment.cached_votes_score = vote_link :minus, vote_comment_path(comment, :dislike), current_user.voted?(comment) === false - = link_to comment.user.login, comment.user.login, class: 'info_title' + = link_to comment.user.login, comment.user, class: 'info_title' .info_muted ' добавил = time_ago_format comment.created_at From 24eb84f26ad55aac3278bc39d62c75b3927addf1 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Thu, 24 Apr 2014 11:39:47 +0300 Subject: [PATCH 54/64] notification group --- app/models/notification/group.rb | 21 ++++++++++++++++ app/models/notification/list.rb | 43 ++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 app/models/notification/group.rb create mode 100644 app/models/notification/list.rb diff --git a/app/models/notification/group.rb b/app/models/notification/group.rb new file mode 100644 index 0000000..2e17983 --- /dev/null +++ b/app/models/notification/group.rb @@ -0,0 +1,21 @@ +class Notification::Group + attr_accessor :notifications, :time, :field, :value + + PERIOD = 30 + FIELDS = [:subject, :user, :target] + + def initialize(time, field, value, notifications = []) + @time = time - PERIOD.minutes + @field = field + @value = value + @notifications = notifications + end + + def accept?(notification) + notification.group_param(field) == value && time < notification.created_at + end + + def user + notifications.first.user + end +end \ No newline at end of file diff --git a/app/models/notification/list.rb b/app/models/notification/list.rb new file mode 100644 index 0000000..822b355 --- /dev/null +++ b/app/models/notification/list.rb @@ -0,0 +1,43 @@ +class Notification::List + def initialize(notifications) + @groups = [] + + notifications.each do |notification| + + create = Notification::Group::FIELDS - append_to_groups(notification) + create.each do |k| + @groups << Notification::Group.new(notification.created_at, k, + notification.group_param(k), [notification]) + end + end + + clear_repeats + end + + def append_to_groups(notification) + [].tap do |exist| + each do |group| + if group.accept?(notification) + group.notifications << notification + exist << group.field + end + end + end.uniq + end + + def each + @groups.each{ |g| yield g } + end + + def clear_repeats + used = {} + weights = [] + @groups.each_with_index{ |g, i| weights << [i, g.notifications.length] } + weights.sort{ |a, b| b[1] <=> a[1] }.each do |w| + @groups[w[0]].notifications.delete_if do |notification| + used[notification.id].tap { used[notification.id] = true } + end + end + @groups.delete_if{ |group| group.notifications.empty? } + end +end \ No newline at end of file From d0be9b4c2edcfa88a4d195ee81f09a311c174401 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Thu, 24 Apr 2014 16:36:50 +0300 Subject: [PATCH 55/64] notification list --- app/assets/javascripts/notification.js.coffee | 10 ++++++ app/assets/stylesheets/funs.css.scss | 33 +++++++++++++++++-- app/controllers/notifications_controller.rb | 5 ++- app/models/ability.rb | 1 + app/models/notification.rb | 9 +++++ app/models/notification/group.rb | 4 +-- app/views/notifications/_group.html.slim | 16 +++++++++ app/views/notifications/_record.html.slim | 15 +++++++++ app/views/notifications/index.html.slim | 22 +++++-------- 9 files changed, 97 insertions(+), 18 deletions(-) create mode 100644 app/assets/javascripts/notification.js.coffee create mode 100644 app/views/notifications/_group.html.slim create mode 100644 app/views/notifications/_record.html.slim diff --git a/app/assets/javascripts/notification.js.coffee b/app/assets/javascripts/notification.js.coffee new file mode 100644 index 0000000..35a8ff2 --- /dev/null +++ b/app/assets/javascripts/notification.js.coffee @@ -0,0 +1,10 @@ +$ -> + marker = '.hidden_mark' + $('.notification_list').on 'click', '.click_handler', (e) -> + e.preventDefault + $this = $ this + $marker = $this.closest(marker) + $group = $this.closest('.notification_group') + + $marker.addClass('hidden') + $group.find('.hidden').not($marker).removeClass('hidden') \ No newline at end of file diff --git a/app/assets/stylesheets/funs.css.scss b/app/assets/stylesheets/funs.css.scss index 3516fd7..ef3c4db 100644 --- a/app/assets/stylesheets/funs.css.scss +++ b/app/assets/stylesheets/funs.css.scss @@ -2351,6 +2351,7 @@ and (orientation:landscape) { font-size: 13px; .info_list_title{ color: #000000; + margin-bottom: 15px; font: { weight: bold; size: 18px; @@ -2379,8 +2380,8 @@ and (orientation:landscape) { } .info_element{ border-top: 1px solid #e2e2e2; - padding-top: 20px; - margin-top: 20px; + padding: 15px 0 0 10px; + margin-top: 15px; position: relative; .info_body{ margin-left: 90px; } .info_title{ @@ -2403,6 +2404,9 @@ and (orientation:landscape) { } .info_list{ margin-left: -60px; + .info_element{ + padding-left: 0; + } } } @@ -2450,4 +2454,29 @@ and (orientation:landscape) { &.plus { left: 0 } &.minus { right: 0 } } +} + +.notification_list{ + .info_element{ + margin-top: 0; + padding-bottom: 15px; + } + .click_handler:hover{ + cursor: pointer; + background-color: #f2f2f2; + + .arrow_expand{ + position: absolute; + top: 15px; + right: 15px; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-top: 6px solid #5b5985; + + &.expanded{ + border-top: 0px solid transparent; + border-bottom: 6px solid #5b5985; + } + } + } } \ No newline at end of file diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb index 3f305cf..cf7d6dc 100644 --- a/app/controllers/notifications_controller.rb +++ b/app/controllers/notifications_controller.rb @@ -3,7 +3,10 @@ class NotificationsController < ApplicationController def index @notifications = Fun.unscoped do - Notification.includes(:user, :target, :subject).where(receiver_id: current_user.id) + Notification.includes(:fun, :user, :target, :subject) + .where(receiver_id: current_user.id).order('created_at DESC').all end + + @list = Notification::List.new(@notifications) end end diff --git a/app/models/ability.rb b/app/models/ability.rb index c2104fa..a6d5a87 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -23,6 +23,7 @@ def initialize(user) cannot :show, Notification else can :read, :all + cannot :read, Notification end end end \ No newline at end of file diff --git a/app/models/notification.rb b/app/models/notification.rb index a23ad1e..6b84277 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -11,4 +11,13 @@ class Notification < ActiveRecord::Base validates_presence_of :subject_id validates_presence_of :user_id validates_presence_of :action + + def group_param(key) + case key + when :subject then "#{subject_type}_#{subject_id}" + when :user then user_id + when :target then target_id ? "#{target_type}_#{target_id}" :fun_id + else nil + end + end end diff --git a/app/models/notification/group.rb b/app/models/notification/group.rb index 2e17983..dea717d 100644 --- a/app/models/notification/group.rb +++ b/app/models/notification/group.rb @@ -15,7 +15,7 @@ def accept?(notification) notification.group_param(field) == value && time < notification.created_at end - def user - notifications.first.user + def first + notifications.first end end \ No newline at end of file diff --git a/app/views/notifications/_group.html.slim b/app/views/notifications/_group.html.slim new file mode 100644 index 0000000..d1b68e7 --- /dev/null +++ b/app/views/notifications/_group.html.slim @@ -0,0 +1,16 @@ +.notification_group + .info_element.click_handler.hidden_mark + .arrow_expand + .photo_frame.pull-left + = link_to show_avatar(group.first.user), group.first.user, class: 'photo_box' + .arrow + + .info_body + | #{group.field} #{group.value} + .info_muted + = time_ago_format group.first.created_at + .info_content= group.notifications.length + .clearfix + .group_details.hidden.hidden_mark + - group.notifications.each_with_index do |notification, index| + = render 'notifications/record', notification: notification, add_class: (index.zero? ? 'click_handler' : '') \ No newline at end of file diff --git a/app/views/notifications/_record.html.slim b/app/views/notifications/_record.html.slim new file mode 100644 index 0000000..0fa3258 --- /dev/null +++ b/app/views/notifications/_record.html.slim @@ -0,0 +1,15 @@ +.info_element class="#{(defined? add_class) ? add_class : ''}" + .arrow_expand.expanded + .photo_frame.pull-left + = link_to show_avatar(notification.user), notification.user, class: 'photo_box' + .arrow + + .info_body + = link_to notification.user.login, notification.user, class: 'info_title' + .info_muted + = time_ago_format notification.created_at + + .info_content + ' #{notification.action} #{notification.subject.class.name} + = link_to notification.target.class.name, notification.target if notification.target + .clearfix \ No newline at end of file diff --git a/app/views/notifications/index.html.slim b/app/views/notifications/index.html.slim index f8937ff..e143ec6 100644 --- a/app/views/notifications/index.html.slim +++ b/app/views/notifications/index.html.slim @@ -1,15 +1,11 @@ .container.rating_layout - .topics_block - .title_page - h1 Notification list .rating_layout - ul - - @notifications.each do |n| - li - .photo_frame - = link_to show_avatar(n.user), n.user, class: 'photo_box' - = link_to n.user.login, n.user - = n.action - = n.subject.class.name - = link_to n.target.class.name, n.target if n.target - = n.created_at \ No newline at end of file + .info_list.notification_list + .info_list_title + ' Notifications list + + - @list.each do |group| + - if group.notifications.length > 1 + = render 'notifications/group', group: group + - else + = render 'notifications/record', notification: group.first \ No newline at end of file From b052c65e92e51fe28dffe436ec446fcbe958193c Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Fri, 25 Apr 2014 15:10:34 +0300 Subject: [PATCH 56/64] notification list --- app/assets/stylesheets/funs.css.scss | 8 ++-- app/controllers/notifications_controller.rb | 2 +- app/helpers/notifications_helper.rb | 24 +++++++++++ app/models/notification.rb | 22 ++++++++-- app/models/notification/group.rb | 21 +++++++++- app/models/notification/list.rb | 7 +++- app/views/notifications/_group.html.slim | 5 ++- app/views/notifications/_record.html.slim | 8 +--- .../notifications/record/_comment.html.slim | 9 +++++ .../notifications/record/_default.html.slim | 8 ++++ config/locales/ru.yml | 40 ++++++++++++++++++- 11 files changed, 133 insertions(+), 21 deletions(-) create mode 100644 app/helpers/notifications_helper.rb create mode 100644 app/views/notifications/record/_comment.html.slim create mode 100644 app/views/notifications/record/_default.html.slim diff --git a/app/assets/stylesheets/funs.css.scss b/app/assets/stylesheets/funs.css.scss index ef3c4db..1aab827 100644 --- a/app/assets/stylesheets/funs.css.scss +++ b/app/assets/stylesheets/funs.css.scss @@ -2384,10 +2384,6 @@ and (orientation:landscape) { margin-top: 15px; position: relative; .info_body{ margin-left: 90px; } - .info_title{ - color: #6d6b93; - &:hover{ text-decoration: underline; } - } .info_muted{ margin-top: 5px; } .info_content{ margin-top: 15px; } .info_action{ display: inline-block; margin-top: 7px; } @@ -2401,6 +2397,10 @@ and (orientation:landscape) { &:hover { > .btn-close-sm { display: block} } + a{ + color: #6d6b93; + &:hover{ text-decoration: underline; } + } } .info_list{ margin-left: -60px; diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb index cf7d6dc..9e53f1e 100644 --- a/app/controllers/notifications_controller.rb +++ b/app/controllers/notifications_controller.rb @@ -3,7 +3,7 @@ class NotificationsController < ApplicationController def index @notifications = Fun.unscoped do - Notification.includes(:fun, :user, :target, :subject) + Notification.includes({ fun: :content } , :user, :target, :subject) .where(receiver_id: current_user.id).order('created_at DESC').all end diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb new file mode 100644 index 0000000..c5ad044 --- /dev/null +++ b/app/helpers/notifications_helper.rb @@ -0,0 +1,24 @@ +module NotificationsHelper + + def notification_group_users(group) + [].tap do |parts| + parts << link_to(group.first.user.login, group.first.user, class: 'info_title') + rest = group.users_count - 1 + parts << t('notification.group.also_users', count: rest) if rest > 0 + end.join(' ').html_safe + end + + def notification_group_actions(group) + [].tap do |parts| + group.collect_msg_keys.each do |action, count| + parts << t("notification.group.#{group.field}.#{action}", count: count) + end + end.join(', ').html_safe + end + + def notification_partial(notification) + partial = (notification.subject_type == 'Comment') ? 'comment' : 'default' + render "notifications/record/#{partial}", notification: notification + end + +end \ No newline at end of file diff --git a/app/models/notification.rb b/app/models/notification.rb index 6b84277..df45ac8 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -14,10 +14,26 @@ class Notification < ActiveRecord::Base def group_param(key) case key - when :subject then "#{subject_type}_#{subject_id}" - when :user then user_id - when :target then target_id ? "#{target_type}_#{target_id}" :fun_id + when :user then "#{user_id}_#{subject_type}_#{target_type}" + when :target then group_target_key else nil end end + + def group_target_key + sub = target_id ? "#{target_type}_#{target_id}" : fun_id + "#{subject_type}_#{sub}" + end + + def msg_key(prefix = true) + [].tap do |parts| + parts.push(:notification) if prefix + parts << normalize_key(subject_type) + parts << (target_id ? normalize_key(target_type) : :fun) + end.join('.') + end + + def normalize_key(key) + key.downcase.gsub(/[^a-z]/, '') + end end diff --git a/app/models/notification/group.rb b/app/models/notification/group.rb index dea717d..e8ed737 100644 --- a/app/models/notification/group.rb +++ b/app/models/notification/group.rb @@ -1,8 +1,9 @@ class Notification::Group attr_accessor :notifications, :time, :field, :value - PERIOD = 30 - FIELDS = [:subject, :user, :target] + PERIOD = 10 + FIELDS = [:target, :user] + WEIGHTS = {target: 2} def initialize(time, field, value, notifications = []) @time = time - PERIOD.minutes @@ -18,4 +19,20 @@ def accept?(notification) def first notifications.first end + + def weight + notifications.length * (WEIGHTS[field] || 1) + end + + def collect_msg_keys + Hash.new(0).tap do |hash| + notifications.each do |notification| + hash[notification.msg_key(false)] += 1 + end + end + end + + def users_count + notifications.collect(&:user_id).uniq.length + end end \ No newline at end of file diff --git a/app/models/notification/list.rb b/app/models/notification/list.rb index 822b355..31581aa 100644 --- a/app/models/notification/list.rb +++ b/app/models/notification/list.rb @@ -11,6 +11,7 @@ def initialize(notifications) end end + remove_illogical clear_repeats end @@ -32,7 +33,7 @@ def each def clear_repeats used = {} weights = [] - @groups.each_with_index{ |g, i| weights << [i, g.notifications.length] } + @groups.each_with_index{ |g, i| weights << [i, g.weight] } weights.sort{ |a, b| b[1] <=> a[1] }.each do |w| @groups[w[0]].notifications.delete_if do |notification| used[notification.id].tap { used[notification.id] = true } @@ -40,4 +41,8 @@ def clear_repeats end @groups.delete_if{ |group| group.notifications.empty? } end + + def remove_illogical + @groups.delete_if{ |group| group.field == :target && group.users_count < 2 } + end end \ No newline at end of file diff --git a/app/views/notifications/_group.html.slim b/app/views/notifications/_group.html.slim index d1b68e7..1c7b45f 100644 --- a/app/views/notifications/_group.html.slim +++ b/app/views/notifications/_group.html.slim @@ -6,10 +6,11 @@ .arrow .info_body - | #{group.field} #{group.value} + = notification_group_users(group) .info_muted = time_ago_format group.first.created_at - .info_content= group.notifications.length + .info_content + = notification_group_actions(group) .clearfix .group_details.hidden.hidden_mark - group.notifications.each_with_index do |notification, index| diff --git a/app/views/notifications/_record.html.slim b/app/views/notifications/_record.html.slim index 0fa3258..6a4eb86 100644 --- a/app/views/notifications/_record.html.slim +++ b/app/views/notifications/_record.html.slim @@ -5,11 +5,5 @@ .arrow .info_body - = link_to notification.user.login, notification.user, class: 'info_title' - .info_muted - = time_ago_format notification.created_at - - .info_content - ' #{notification.action} #{notification.subject.class.name} - = link_to notification.target.class.name, notification.target if notification.target + = notification_partial(notification) .clearfix \ No newline at end of file diff --git a/app/views/notifications/record/_comment.html.slim b/app/views/notifications/record/_comment.html.slim new file mode 100644 index 0000000..d784ed3 --- /dev/null +++ b/app/views/notifications/record/_comment.html.slim @@ -0,0 +1,9 @@ += link_to notification.user.login, notification.user +.info_muted + = time_ago_format notification.created_at + ' + = t(notification.msg_key) + ' + = link_to(notification.fun.content.title ? notification.fun.content.title : 'фану', notification.fun) +.info_content + = notification.subject.body \ No newline at end of file diff --git a/app/views/notifications/record/_default.html.slim b/app/views/notifications/record/_default.html.slim new file mode 100644 index 0000000..41ac809 --- /dev/null +++ b/app/views/notifications/record/_default.html.slim @@ -0,0 +1,8 @@ += link_to notification.user.login, notification.user +.info_muted + = time_ago_format notification.created_at + +.info_content + = t(notification.msg_key) + ' + = link_to(notification.fun.content.title.empty? ? 'фан' : notification.fun.content.title , notification.fun) \ No newline at end of file diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 0e0ac29..bd69a42 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -211,4 +211,42 @@ ru: button: new: Добавить комментарий create: Сохранить комментарий - answer: Ответить \ No newline at end of file + answer: Ответить + notification: + group: + also_users: + zero: + one: и еще %{count} пользователь + few: и еще %{count} пользователя + other: и еще %{count} пользователей + user: + actsasvotablevote: + fun: + one: оценил Ваш фан + few: оценил %{count} Ваших фана + other: оценил %{count} Ваших фанов + comment: + one: оценил Ваш комментарий + few: оценил %{count} Ваш комментария + other: оценил %{count} Ваш комментариев + comment: + fun: + one: откомментировал Ваш фан + few: добавил %{count} комментария к Вашим фанам + other: добавил %{count} комментариев к Вашим фанам + comment: + one: ответил на Ваш коментарий + few: оставил %{count} ответа к Вашим комментариям + other: оставил %{count} ответов к Вашим комментариям + target: + comment: + fun: откомментировали Ваш фан + actsasvotablevote: + fun: оценили Ваш фан + + actsasvotablevote: + fun: понравился + comment: понравился комментарий к + comment: + comment: в ответах на комментарий к + fun: в комментариях к \ No newline at end of file From bee2df8266c1c6f880b87fba53b18da507115e80 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Fri, 25 Apr 2014 16:18:54 +0300 Subject: [PATCH 57/64] notification list (small photos) --- app/assets/stylesheets/funs.css.scss | 5 +++++ app/views/notifications/_group.html.slim | 3 +-- app/views/notifications/_record.html.slim | 3 +-- app/views/notifications/record/_comment.html.slim | 3 ++- app/views/notifications/record/_default.html.slim | 3 ++- config/locales/ru.yml | 2 +- 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/app/assets/stylesheets/funs.css.scss b/app/assets/stylesheets/funs.css.scss index 1aab827..677d643 100644 --- a/app/assets/stylesheets/funs.css.scss +++ b/app/assets/stylesheets/funs.css.scss @@ -2460,6 +2460,11 @@ and (orientation:landscape) { .info_element{ margin-top: 0; padding-bottom: 15px; + .info_body{ + margin-left: 50px; + margin-right: 40px; + } + .info_content{ margin-top: 5px} } .click_handler:hover{ cursor: pointer; diff --git a/app/views/notifications/_group.html.slim b/app/views/notifications/_group.html.slim index 1c7b45f..9085c2c 100644 --- a/app/views/notifications/_group.html.slim +++ b/app/views/notifications/_group.html.slim @@ -1,9 +1,8 @@ .notification_group .info_element.click_handler.hidden_mark .arrow_expand - .photo_frame.pull-left + .photo_frame.pull-left.photo_frame_sm = link_to show_avatar(group.first.user), group.first.user, class: 'photo_box' - .arrow .info_body = notification_group_users(group) diff --git a/app/views/notifications/_record.html.slim b/app/views/notifications/_record.html.slim index 6a4eb86..ee2ae04 100644 --- a/app/views/notifications/_record.html.slim +++ b/app/views/notifications/_record.html.slim @@ -1,8 +1,7 @@ .info_element class="#{(defined? add_class) ? add_class : ''}" .arrow_expand.expanded - .photo_frame.pull-left + .photo_frame.pull-left.photo_frame_sm = link_to show_avatar(notification.user), notification.user, class: 'photo_box' - .arrow .info_body = notification_partial(notification) diff --git a/app/views/notifications/record/_comment.html.slim b/app/views/notifications/record/_comment.html.slim index d784ed3..d17adde 100644 --- a/app/views/notifications/record/_comment.html.slim +++ b/app/views/notifications/record/_comment.html.slim @@ -1,5 +1,6 @@ = link_to notification.user.login, notification.user -.info_muted +' +span.info_muted = time_ago_format notification.created_at ' = t(notification.msg_key) diff --git a/app/views/notifications/record/_default.html.slim b/app/views/notifications/record/_default.html.slim index 41ac809..de69551 100644 --- a/app/views/notifications/record/_default.html.slim +++ b/app/views/notifications/record/_default.html.slim @@ -1,5 +1,6 @@ = link_to notification.user.login, notification.user -.info_muted +' +span.info_muted = time_ago_format notification.created_at .info_content diff --git a/config/locales/ru.yml b/config/locales/ru.yml index bd69a42..2036508 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -228,7 +228,7 @@ ru: comment: one: оценил Ваш комментарий few: оценил %{count} Ваш комментария - other: оценил %{count} Ваш комментариев + other: оценил %{count} Ваших комментариев comment: fun: one: откомментировал Ваш фан From 16fd0f85a8c11c630b29d46d7e97850fa7eba18b Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Fri, 25 Apr 2014 18:05:51 +0300 Subject: [PATCH 58/64] notification list (fix) --- app/assets/stylesheets/funs.css.scss | 8 ++++---- app/helpers/notifications_helper.rb | 18 +++++++++++++++++- app/views/comments/_comment.html.slim | 2 +- app/views/notifications/_group.html.slim | 3 +++ .../notifications/record/_comment.html.slim | 4 ++-- .../notifications/record/_default.html.slim | 4 ++-- config/locales/ru.yml | 7 +++++-- lib/acts_as_votable/vote.rb | 2 +- 8 files changed, 35 insertions(+), 13 deletions(-) diff --git a/app/assets/stylesheets/funs.css.scss b/app/assets/stylesheets/funs.css.scss index 677d643..b706bfc 100644 --- a/app/assets/stylesheets/funs.css.scss +++ b/app/assets/stylesheets/funs.css.scss @@ -2397,10 +2397,10 @@ and (orientation:landscape) { &:hover { > .btn-close-sm { display: block} } - a{ - color: #6d6b93; - &:hover{ text-decoration: underline; } - } + } + .info_link{ + color: #6d6b93; + &:hover{ text-decoration: underline; } } .info_list{ margin-left: -60px; diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index c5ad044..4d4e8f3 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -2,7 +2,7 @@ module NotificationsHelper def notification_group_users(group) [].tap do |parts| - parts << link_to(group.first.user.login, group.first.user, class: 'info_title') + parts << link_to(group.first.user.login, group.first.user, class: 'info_link') rest = group.users_count - 1 parts << t('notification.group.also_users', count: rest) if rest > 0 end.join(' ').html_safe @@ -21,4 +21,20 @@ def notification_partial(notification) render "notifications/record/#{partial}", notification: notification end + def notification_fun_link(notification, prefix = false) + + unless prefix + prefix = 'funs.forms.w1' + if [notification.subject_type, notification.target_type].include? 'Comment' + prefix = 'funs.forms.w2' + end + end + + if notification.fun.content.title.empty? + link_to(t(prefix), notification.fun, class: 'info_link') + else + "#{t(prefix)} #{link_to(notification.fun.content.title, notification.fun, class: 'info_link')}".html_safe + end + end + end \ No newline at end of file diff --git a/app/views/comments/_comment.html.slim b/app/views/comments/_comment.html.slim index ea3752f..da3bbb1 100644 --- a/app/views/comments/_comment.html.slim +++ b/app/views/comments/_comment.html.slim @@ -12,7 +12,7 @@ span.vote_result= comment.cached_votes_score = vote_link :minus, vote_comment_path(comment, :dislike), current_user.voted?(comment) === false - = link_to comment.user.login, comment.user, class: 'info_title' + = link_to comment.user.login, comment.user, class: 'info_link' .info_muted ' добавил = time_ago_format comment.created_at diff --git a/app/views/notifications/_group.html.slim b/app/views/notifications/_group.html.slim index 9085c2c..8d6700b 100644 --- a/app/views/notifications/_group.html.slim +++ b/app/views/notifications/_group.html.slim @@ -10,6 +10,9 @@ = time_ago_format group.first.created_at .info_content = notification_group_actions(group) + - if group.field == :target + ' + = notification_fun_link(group.first) .clearfix .group_details.hidden.hidden_mark - group.notifications.each_with_index do |notification, index| diff --git a/app/views/notifications/record/_comment.html.slim b/app/views/notifications/record/_comment.html.slim index d17adde..4162904 100644 --- a/app/views/notifications/record/_comment.html.slim +++ b/app/views/notifications/record/_comment.html.slim @@ -1,10 +1,10 @@ -= link_to notification.user.login, notification.user += link_to notification.user.login, notification.user, class: 'info_link' ' span.info_muted = time_ago_format notification.created_at ' = t(notification.msg_key) ' - = link_to(notification.fun.content.title ? notification.fun.content.title : 'фану', notification.fun) + = notification_fun_link(notification) .info_content = notification.subject.body \ No newline at end of file diff --git a/app/views/notifications/record/_default.html.slim b/app/views/notifications/record/_default.html.slim index de69551..235b9b7 100644 --- a/app/views/notifications/record/_default.html.slim +++ b/app/views/notifications/record/_default.html.slim @@ -1,4 +1,4 @@ -= link_to notification.user.login, notification.user += link_to notification.user.login, notification.user, class: 'info_link' ' span.info_muted = time_ago_format notification.created_at @@ -6,4 +6,4 @@ span.info_muted .info_content = t(notification.msg_key) ' - = link_to(notification.fun.content.title.empty? ? 'фан' : notification.fun.content.title , notification.fun) \ No newline at end of file + = notification_fun_link(notification) \ No newline at end of file diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 2036508..7ac487e 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -75,6 +75,9 @@ ru: social_likes: "Проголосовать в соц сетях" edit: "Редактировать фан" update_error: "Произошла ошибка при сохранении фана :( Проверьте данные и повторите попытку" + forms: + w1: фан + w2: фанy reposts: created: "Фан успешно скопирован вам на стену." button: "Репостить" @@ -240,9 +243,9 @@ ru: other: оставил %{count} ответов к Вашим комментариям target: comment: - fun: откомментировали Ваш фан + fun: откомментировали actsasvotablevote: - fun: оценили Ваш фан + fun: оценили actsasvotablevote: fun: понравился diff --git a/lib/acts_as_votable/vote.rb b/lib/acts_as_votable/vote.rb index bd7f6b7..590a250 100644 --- a/lib/acts_as_votable/vote.rb +++ b/lib/acts_as_votable/vote.rb @@ -11,7 +11,7 @@ def create_notification data = { user_id: voter_id, action: :create, receiver_id: votable.user_id } data[:fun] = votable.notification_fun if votable.respond_to? :notification_fun - data[:target] = votable unless data[:fun] || data[:fun] == votable + data[:target] = votable unless data[:fun] && data[:fun] == votable notifications.create(data) end From dc7722c4f54624a424ba2d98eccad32e01730c26 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Mon, 28 Apr 2014 10:10:40 +0300 Subject: [PATCH 59/64] fix condition in fun_image_path --- app/helpers/funs_helper.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/helpers/funs_helper.rb b/app/helpers/funs_helper.rb index 6aef9ff..6bb262c 100644 --- a/app/helpers/funs_helper.rb +++ b/app/helpers/funs_helper.rb @@ -166,10 +166,10 @@ def report_fun_link(fun) def fun_image_path(fun, versions = {}) type = fun.content.class.to_s column = type == 'Image' ? :file : :image # fun.content.class.uploaders - unless type == 'Post' - fun.content.try(column).url(*versions) - else + if type == 'Post' asset_path('social_logo.png') + else + fun.content.try(column).url(*versions) end end From ea5d61bf3d50d919d8cc274da9ab4b62f566c4d0 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Mon, 28 Apr 2014 10:41:08 +0300 Subject: [PATCH 60/64] notification fun preview --- app/assets/stylesheets/funs.css.scss | 14 ++++++++++++-- app/helpers/notifications_helper.rb | 6 ++++++ app/views/notifications/_record.html.slim | 2 ++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/funs.css.scss b/app/assets/stylesheets/funs.css.scss index b706bfc..1a2d201 100644 --- a/app/assets/stylesheets/funs.css.scss +++ b/app/assets/stylesheets/funs.css.scss @@ -2383,7 +2383,10 @@ and (orientation:landscape) { padding: 15px 0 0 10px; margin-top: 15px; position: relative; - .info_body{ margin-left: 90px; } + .info_body{ + margin-left: 90px; + word-wrap: break-word; + } .info_muted{ margin-top: 5px; } .info_content{ margin-top: 15px; } .info_action{ display: inline-block; margin-top: 7px; } @@ -2464,7 +2467,14 @@ and (orientation:landscape) { margin-left: 50px; margin-right: 40px; } - .info_content{ margin-top: 5px} + .info_content{ margin-top: 5px } + .preview{ + float: right; + width: 50px; + max-height: 50px; + overflow: hidden; + img{ width: 100%; } + } } .click_handler:hover{ cursor: pointer; diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index 4d4e8f3..65e0eb2 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -37,4 +37,10 @@ def notification_fun_link(notification, prefix = false) end end + def notification_fun_preview(notification) + unless notification.fun.content_type == 'Post' + link_to fun_image(notification.fun, version: :small), notification.fun, class: 'preview' + end + end + end \ No newline at end of file diff --git a/app/views/notifications/_record.html.slim b/app/views/notifications/_record.html.slim index ee2ae04..3a6e7ff 100644 --- a/app/views/notifications/_record.html.slim +++ b/app/views/notifications/_record.html.slim @@ -4,5 +4,7 @@ = link_to show_avatar(notification.user), notification.user, class: 'photo_box' .info_body + = notification_fun_preview(notification) + = notification_partial(notification) .clearfix \ No newline at end of file From 654baa532c1c3537de45776441f626a26ffcf499 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Mon, 28 Apr 2014 15:28:25 +0300 Subject: [PATCH 61/64] notification endless --- app/assets/javascripts/notification.js.coffee | 35 +++++++++++++++++-- app/controllers/notifications_controller.rb | 10 +++--- app/models/notification.rb | 2 ++ app/models/user.rb | 12 +++++++ app/views/notifications/_list.html.slim | 8 +++++ app/views/notifications/index.html.slim | 6 +--- app/views/notifications/index.js.slim | 1 + 7 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 app/views/notifications/_list.html.slim create mode 100644 app/views/notifications/index.js.slim diff --git a/app/assets/javascripts/notification.js.coffee b/app/assets/javascripts/notification.js.coffee index 35a8ff2..d193dab 100644 --- a/app/assets/javascripts/notification.js.coffee +++ b/app/assets/javascripts/notification.js.coffee @@ -1,10 +1,41 @@ $ -> marker = '.hidden_mark' - $('.notification_list').on 'click', '.click_handler', (e) -> + $list = $('.notification_list').on 'click', '.click_handler', (e) -> e.preventDefault $this = $ this $marker = $this.closest(marker) $group = $this.closest('.notification_group') $marker.addClass('hidden') - $group.find('.hidden').not($marker).removeClass('hidden') \ No newline at end of file + $group.find('.hidden').not($marker).removeClass('hidden') + + if ($list.length) + $(window).endlessScroll + fireOnce: true, + fireDelay: false, + intervalFrequency: 250, + inflowPixels: 200, + loader: '', + ceaseFireOnEmpty: false, + callback: () -> + window.endlessScrolllLoading = true; + url = $('input[name=next]').last().val() + + return false unless url + + $('
').insertAfter($list) + $.ajax + cache: false + url: url + complete: (data) -> + return true unless (data.status == 200) + + $(window).data('endelessscroll').stopFiring() unless data.responseText.length + window.endlessScrolllLoading = false + $elements = $(data.responseText) + + $elements.initButtonTooltips() + $elements.initTooltips() + $elements.findAndFormatDateTime() + $list.append($elements) + $('#loading').remove() \ No newline at end of file diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb index 9e53f1e..633aa22 100644 --- a/app/controllers/notifications_controller.rb +++ b/app/controllers/notifications_controller.rb @@ -1,12 +1,12 @@ class NotificationsController < ApplicationController authorize_resource - def index - @notifications = Fun.unscoped do - Notification.includes({ fun: :content } , :user, :target, :subject) - .where(receiver_id: current_user.id).order('created_at DESC').all - end + respond_to :html, :js + def index + @notifications = current_user.notifications_before(params[:date]) @list = Notification::List.new(@notifications) + + respond_with(@notifications, @list) end end diff --git a/app/models/notification.rb b/app/models/notification.rb index df45ac8..2c82481 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -12,6 +12,8 @@ class Notification < ActiveRecord::Base validates_presence_of :user_id validates_presence_of :action + scope :limited, limit(30) + def group_param(key) case key when :user then "#{user_id}_#{subject_type}_#{target_type}" diff --git a/app/models/user.rb b/app/models/user.rb index f502cf4..a7fd734 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -47,6 +47,8 @@ def funs_with_reposts # Authorization services (FB, VK, TW) has_many :identities + has_many :notifications, foreign_key: :receiver_id + # Validation rules validates :email, uniqueness: true, format: { with: email_regexp }, if: :email_required? @@ -220,6 +222,16 @@ def send_welcome_email UserMailer.welcome_email(self).deliver if email.present? end + def notifications_before(date = null) + Fun.unscoped do + query = notifications.includes({ fun: :content }, :user, :target, :subject) + + query = query.where('created_at < ?', date) if date + + query.order('created_at DESC').limited.all + end + end + class << self def sort_column(column) diff --git a/app/views/notifications/_list.html.slim b/app/views/notifications/_list.html.slim new file mode 100644 index 0000000..df5ce0e --- /dev/null +++ b/app/views/notifications/_list.html.slim @@ -0,0 +1,8 @@ +- list.each do |group| + - if group.notifications.length > 1 + = render 'notifications/group', group: group + - else + = render 'notifications/record', notification: group.first + +- unless notifications.length.zero? + input type='hidden' name='next' value=url_for(format: :js, date: notifications.last.created_at) \ No newline at end of file diff --git a/app/views/notifications/index.html.slim b/app/views/notifications/index.html.slim index e143ec6..eab3b93 100644 --- a/app/views/notifications/index.html.slim +++ b/app/views/notifications/index.html.slim @@ -4,8 +4,4 @@ .info_list_title ' Notifications list - - @list.each do |group| - - if group.notifications.length > 1 - = render 'notifications/group', group: group - - else - = render 'notifications/record', notification: group.first \ No newline at end of file + = render 'list', list: @list, notifications: @notifications \ No newline at end of file diff --git a/app/views/notifications/index.js.slim b/app/views/notifications/index.js.slim new file mode 100644 index 0000000..af38283 --- /dev/null +++ b/app/views/notifications/index.js.slim @@ -0,0 +1 @@ += render 'list', list: @list, notifications: @notifications \ No newline at end of file From 33a59a3cab67379d8c3f5e84b6f1f8d1ed090a46 Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Mon, 28 Apr 2014 15:33:53 +0300 Subject: [PATCH 62/64] notification link in dropdown --- app/views/layouts/_header.html.slim | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/layouts/_header.html.slim b/app/views/layouts/_header.html.slim index 8d9bbcf..299b1cc 100644 --- a/app/views/layouts/_header.html.slim +++ b/app/views/layouts/_header.html.slim @@ -28,6 +28,7 @@ header.main_panel[role="banner"] ul.top li = link_to 'Моя страница', user_path(current_user) li = link_to 'Мои подписки', feed_path + li = link_to 'Мои уведомления', notifications_path - if can? :read, Report li = link_to "Жалобы (#{Report.count})", reports_path ul.down From 42667109748cd7a3f42cae78f2198adcfdbc10fe Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Mon, 28 Apr 2014 15:38:33 +0300 Subject: [PATCH 63/64] notification index title i18n --- app/views/notifications/index.html.slim | 4 ++-- config/locales/ru.yml | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/views/notifications/index.html.slim b/app/views/notifications/index.html.slim index eab3b93..86e9c9e 100644 --- a/app/views/notifications/index.html.slim +++ b/app/views/notifications/index.html.slim @@ -1,7 +1,7 @@ .container.rating_layout .rating_layout .info_list.notification_list - .info_list_title - ' Notifications list + .info_list_title= t 'notification.title.index' + = render 'list', list: @list, notifications: @notifications \ No newline at end of file diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 7ac487e..6244705 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -252,4 +252,6 @@ ru: comment: понравился комментарий к comment: comment: в ответах на комментарий к - fun: в комментариях к \ No newline at end of file + fun: в комментариях к + title: + index: Мои уведомления \ No newline at end of file From 6270255728bc2e5d92fad792958304ab32e79eff Mon Sep 17 00:00:00 2001 From: Blaze34 <30avenyamadeo@gmail.com> Date: Mon, 28 Apr 2014 16:16:16 +0300 Subject: [PATCH 64/64] fix scripts --- app/assets/javascripts/funs/wall.js | 5 ++--- app/assets/javascripts/users/wall.js | 17 ++++++++++------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/funs/wall.js b/app/assets/javascripts/funs/wall.js index 7d45b0c..e450d80 100644 --- a/app/assets/javascripts/funs/wall.js +++ b/app/assets/javascripts/funs/wall.js @@ -100,8 +100,7 @@ $(function(){ url: url, dataType: 'script', complete: function(data) { - if (data.status == 200) - { + if (data.status == 200){ $('#next_url').data('url', url.replace('page=' + (i + 1), 'page=' + (i + 2))); if (data.responseText.length == 0) $(window).data('endelessscroll').stopFiring(); @@ -114,8 +113,8 @@ $(function(){ $newElems.findAndFormatDateTime(); if ($wall.data('masonry')) $wall.masonry( 'appended', $newElems, true ); $wall.append($newElems); + $('#loading').remove(); }); - $('#loading').remove(); } } }); diff --git a/app/assets/javascripts/users/wall.js b/app/assets/javascripts/users/wall.js index c8598a6..121dc88 100644 --- a/app/assets/javascripts/users/wall.js +++ b/app/assets/javascripts/users/wall.js @@ -24,8 +24,7 @@ $(function(){ data: { view: currentState }, dataType: 'script', complete: function(data) { - if (data.status == 200) - { + if (data.status == 200){ var wall = $('.post_wall'); wall.html(data.responseText); @@ -36,8 +35,10 @@ $(function(){ if (currentState == 'box'){ layout.addClass('grid'); - if (wall.data('masonry')) wall.masonry('reload'); - else wall.masonry({ itemSelector : '.post_card', gutterWidth: 20 }) + wall.imagesLoaded(function(){ + if (wall.data('masonry')) wall.masonry('reload'); + else wall.masonry({ itemSelector : '.post_card', gutterWidth: 20 }) + }); } else{ if (wall.data('masonry')) wall.masonry('destroy'); @@ -60,8 +61,7 @@ $(function(){ url: url, dataType: 'script', complete: function(data) { - if (data.status == 200) - { + if (data.status == 200){ var wall = $('.post_wall'); wall.html(data.responseText); wall.initButtonTooltips(); @@ -69,7 +69,10 @@ $(function(){ wall.findAndFormatDateTime(); $(window).data('endelessscroll').resetFiring(); if (currentState == 'box'){ - if (wall.data('masonry')) wall.masonry('reload'); + wall.imagesLoaded(function(){ + if (wall.data('masonry')) wall.masonry('reload'); + else wall.masonry({ itemSelector : '.post_card', gutterWidth: 20 }) + }); } } $('#ajax_loading').remove();