chat 0.0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +47 -22
  4. data/Rakefile +27 -1
  5. data/app/assets/config/chat_manifest.js +2 -0
  6. data/app/assets/javascripts/chat.js +16 -0
  7. data/app/assets/javascripts/chat/cable.js +13 -0
  8. data/app/assets/javascripts/chat/channels/message.coffee +75 -0
  9. data/app/assets/javascripts/chat/channels/notification.coffee +44 -0
  10. data/app/assets/javascripts/chat/channels/status.coffee +13 -0
  11. data/app/assets/javascripts/chat/emojionearea.min.js +1 -0
  12. data/app/assets/javascripts/chat/messages.coffee +44 -0
  13. data/app/assets/stylesheets/chat.css +15 -0
  14. data/app/assets/stylesheets/chat/chat.sass +25 -0
  15. data/app/assets/stylesheets/chat/checkbox.sass +80 -0
  16. data/app/assets/stylesheets/chat/emojionearea.min.css +1 -0
  17. data/app/assets/stylesheets/chat/header.sass +50 -0
  18. data/app/assets/stylesheets/chat/launch.sass +26 -0
  19. data/app/assets/stylesheets/chat/list.sass +45 -0
  20. data/app/assets/stylesheets/chat/message_form.sass +50 -0
  21. data/app/assets/stylesheets/chat/new.sass +53 -0
  22. data/app/assets/stylesheets/chat/transcript.sass +76 -0
  23. data/app/channels/chat/messages_channel.rb +11 -0
  24. data/app/channels/chat/notification_channel.rb +10 -0
  25. data/app/channels/chat/status_channel.rb +12 -0
  26. data/app/controllers/chat/application_controller.rb +5 -0
  27. data/app/controllers/chat/conversations_controller.rb +30 -0
  28. data/app/controllers/chat/messages_controller.rb +28 -0
  29. data/app/helpers/chat/application_helper.rb +62 -0
  30. data/app/jobs/chat/application_job.rb +5 -0
  31. data/app/jobs/chat/message_relay_job.rb +40 -0
  32. data/app/jobs/chat/notification_relay_job.rb +11 -0
  33. data/app/jobs/chat/status_relay_job.rb +9 -0
  34. data/app/mailers/chat/application_mailer.rb +6 -0
  35. data/app/models/chat/application_record.rb +3 -0
  36. data/app/models/chat/conversation.rb +9 -0
  37. data/app/models/chat/dot_command.rb +26 -0
  38. data/app/models/chat/dot_command/gif.rb +17 -0
  39. data/app/models/chat/dot_command/leave.rb +16 -0
  40. data/app/models/chat/dot_command/shrug.rb +27 -0
  41. data/app/models/chat/dot_command/validator.rb +23 -0
  42. data/app/models/chat/message.rb +29 -0
  43. data/app/models/chat/session.rb +10 -0
  44. data/app/views/chat/_chat.html.haml +14 -0
  45. data/app/views/chat/conversations/_index.html.haml +11 -0
  46. data/app/views/chat/conversations/_new.html.haml +10 -0
  47. data/app/views/chat/conversations/_show.html.haml +9 -0
  48. data/app/views/chat/conversations/create.js.erb +21 -0
  49. data/app/views/chat/conversations/show.js.erb +12 -0
  50. data/app/views/chat/messages/_message.haml +13 -0
  51. data/app/views/layouts/chat/application.html.erb +14 -0
  52. data/config/routes.rb +5 -0
  53. data/lib/chat.rb +29 -3
  54. data/lib/chat/engine.rb +5 -0
  55. data/lib/chat/user.rb +51 -0
  56. data/lib/chat/version.rb +1 -1
  57. data/lib/generators/chat/install/install_generator.rb +68 -0
  58. data/lib/generators/chat/install/templates/add_chat_to_users.rb +9 -0
  59. data/lib/generators/chat/install/templates/chat.rb +11 -0
  60. data/lib/generators/chat/install/templates/create_chat.rb +29 -0
  61. data/lib/tasks/chat_tasks.rake +4 -0
  62. metadata +296 -16
  63. data/.gitignore +0 -9
  64. data/Gemfile +0 -4
  65. data/LICENSE.txt +0 -21
  66. data/bin/console +0 -14
  67. data/bin/setup +0 -8
  68. data/chat.gemspec +0 -22
@@ -0,0 +1 @@
1
+ .dropdown-menu.textcomplete-dropdown[data-strategy=emojionearea]{position:absolute;z-index:1000;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;-moz-box-shadow:0 6px 12px rgba(0,0,0,.175);-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.textcomplete-dropdown[data-strategy=emojionearea] li.textcomplete-item{font-size:14px;padding:1px 3px;border:0}.dropdown-menu.textcomplete-dropdown[data-strategy=emojionearea] li.textcomplete-item a{text-decoration:none;display:block;height:100%;line-height:1.8em;padding:0 1.54em 0 .615em;color:#4f4f4f}.dropdown-menu.textcomplete-dropdown[data-strategy=emojionearea] li.textcomplete-item.active,.dropdown-menu.textcomplete-dropdown[data-strategy=emojionearea] li.textcomplete-item:hover{background-color:#e4e4e4}.dropdown-menu.textcomplete-dropdown[data-strategy=emojionearea] li.textcomplete-item.active a,.dropdown-menu.textcomplete-dropdown[data-strategy=emojionearea] li.textcomplete-item:hover a{color:#333}.dropdown-menu.textcomplete-dropdown[data-strategy=emojionearea] li.textcomplete-item .emojioneemoji{font-size:inherit;height:2ex;width:2.1ex;min-height:20px;min-width:20px;display:inline-block;margin:0 5px .2ex 0;line-height:normal;vertical-align:middle;max-width:100%;top:0}.emojionearea,.emojionearea *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.emojionearea,.emojionearea.form-control{display:block;position:relative!important;width:100%;height:auto;padding:0;font-size:14px}.emojionearea .emojionearea-editor{display:block;height:auto;max-height:80px;overflow:auto;padding:6px 57px 6px 0;line-height:1.42857143;font-size:17px;color:#212121;background-color:transparent;border:0;cursor:text;margin-right:1px;border-bottom:1px solid rgba(0,0,0,.26);word-wrap:break-word}.emojionearea .emojionearea-editor:empty:before{content:attr(placeholder);display:block;color:#bbb}.emojionearea .emojionearea-editor:focus{border:0;outline:0;-moz-box-shadow:none;-webkit-box-shadow:none;box-shadow:none}.emojionearea .emojionearea-editor .emojioneemoji,.emojionearea .emojionearea-editor [class*=emojione-]{font-size:inherit;height:2ex;width:2.1ex;min-height:20px;min-width:20px;display:inline-block;margin:-.2ex .15em .2ex;line-height:normal;vertical-align:middle;max-width:100%;top:0}.emojionearea.emojionearea-inline{height:34px}.emojionearea.emojionearea-inline>.emojionearea-editor{height:32px;min-height:20px;overflow:hidden;white-space:nowrap;position:absolute;top:0;left:12px;right:24px;padding:6px 0}.emojionearea.emojionearea-inline>.emojionearea-button{top:4px}.emojionearea .emojionearea-button{z-index:5;position:absolute;right:3px;top:3px;width:24px;height:24px;opacity:.6;cursor:pointer;-moz-transition:opacity .3s ease-in-out;-o-transition:opacity .3s ease-in-out;-webkit-transition:opacity .3s ease-in-out;transition:opacity .3s ease-in-out}.emojionearea .emojionearea-button:hover{opacity:1}.emojionearea .emojionearea-button>div{display:block;width:24px;height:24px;position:absolute;-moz-transition:all .4s ease-in-out;-o-transition:all .4s ease-in-out;-webkit-transition:all .4s ease-in-out;transition:all .4s ease-in-out}.emojionearea .emojionearea-button>div.emojionearea-button-open{background-position:0 -24px;filter:alpha(enabled=false);opacity:1}.emojionearea .emojionearea-button>div.emojionearea-button-close{background-position:0 0;-webkit-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg);filter:alpha(Opacity=0);opacity:0}.emojionearea .emojionearea-button.active>div.emojionearea-button-open{-webkit-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);filter:alpha(Opacity=0);opacity:0}.emojionearea .emojionearea-button.active>div.emojionearea-button-close{-webkit-transform:rotate(0);-o-transform:rotate(0);transform:rotate(0);filter:alpha(enabled=false);opacity:1}.emojionearea .emojionearea-picker{background:#fff;position:absolute;-moz-box-shadow:0 1px 5px rgba(0,0,0,.32);-webkit-box-shadow:0 1px 5px rgba(0,0,0,.32);box-shadow:0 1px 5px rgba(0,0,0,.32);-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;height:236px;width:316px;top:-15px;right:-15px;z-index:90;-moz-transition:all .25s ease-in-out;-o-transition:all .25s ease-in-out;-webkit-transition:all .25s ease-in-out;transition:all .25s ease-in-out;filter:alpha(Opacity=0);opacity:0;-moz-user-select:-moz-none;-ms-user-select:none;-webkit-user-select:none;user-select:none}.emojionearea .emojionearea-picker.hidden{display:none}.emojionearea .emojionearea-picker .emojionearea-wrapper{position:relative;height:236px;width:316px}.emojionearea .emojionearea-picker .emojionearea-wrapper:after{content:"";display:block;position:absolute;background-repeat:no-repeat;z-index:91}.emojionearea .emojionearea-picker .emojionearea-filters{width:100%;position:absolute;background:#F5F7F9;padding:0 0 0 7px;height:40px;z-index:95}.emojionearea .emojionearea-picker .emojionearea-filters .emojionearea-filter{display:block;float:left;height:40px;width:32px;padding:7px 1px 0;cursor:pointer;-webkit-filter:grayscale(1);filter:grayscale(1)}.emojionearea .emojionearea-picker .emojionearea-filters .emojionearea-filter.active{background:#fff}.emojionearea .emojionearea-picker .emojionearea-filters .emojionearea-filter.active,.emojionearea .emojionearea-picker .emojionearea-filters .emojionearea-filter:hover{-webkit-filter:grayscale(0);filter:grayscale(0)}.emojionearea .emojionearea-picker .emojionearea-filters .emojionearea-filter>i{width:24px;height:24px;top:0}.emojionearea .emojionearea-picker .emojionearea-filters .emojionearea-filter>img{width:24px;height:24px;margin:0 3px}.emojionearea .emojionearea-picker .emojionearea-scroll-area{height:196px;overflow:auto;overflow-x:hidden;width:100%;position:absolute;padding:0 0 5px}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-emojis-list{z-index:1}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones{position:absolute;top:6px;right:10px;height:22px;z-index:2}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone{display:inline-block;padding:0;border:0;vertical-align:middle;outline:0;background:0 0;cursor:pointer;position:relative}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-0,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-0:after{background-color:#ffcf3e}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-1,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-1:after{background-color:#fae3c5}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-2,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-2:after{background-color:#e2cfa5}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-3,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-3:after{background-color:#daa478}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-4,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-4:after{background-color:#a78058}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-5,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-5:after{background-color:#5e4d43}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-bullet>.btn-tone,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-square>.btn-tone{width:20px;height:20px;margin:0;background-color:transparent}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-bullet>.btn-tone:after,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-square>.btn-tone:after{content:"";position:absolute;display:block;top:4px;left:4px;width:12px;height:12px}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-bullet>.btn-tone.active:after,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-square>.btn-tone.active:after{top:0;left:0;width:20px;height:20px}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-checkbox>.btn-tone,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-radio>.btn-tone{width:16px;height:16px;margin:0 2px}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-checkbox>.btn-tone.active:after,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-radio>.btn-tone.active:after{content:"";position:absolute;display:block;background-color:transparent;border:2px solid #fff;width:8px;height:8px;top:2px;left:2px}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-category:after,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-category:before,.emojionearea .emojionearea-picker .emojionearea-scroll-area h1:after,.emojionearea .emojionearea-picker .emojionearea-scroll-area h1:before{content:" ";clear:both;display:block}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-bullet>.btn-tone,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-bullet>.btn-tone:after,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-radio>.btn-tone,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-radio>.btn-tone:after{-moz-border-radius:100%;-webkit-border-radius:100%;border-radius:100%}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-checkbox>.btn-tone,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-checkbox>.btn-tone:after,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-square>.btn-tone,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-square>.btn-tone:after{-moz-border-radius:1px;-webkit-border-radius:1px;border-radius:1px}.emojionearea .emojionearea-picker .emojionearea-scroll-area h1{display:block;font-family:Arial,'Helvetica Neue',Helvetica,sans-serif;font-size:13px;font-weight:400;color:#b2b2b2;background:#fff;line-height:20px;margin:0;padding:7px 0 5px 6px}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-category{padding:0 0 0 7px}.emojionearea .emojionearea-picker .emojionearea-scroll-area [class*=emojione-]{-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;margin:0;width:24px;height:24px;top:0}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojibtn{-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;width:24px;height:24px;float:left;display:block;margin:1px;padding:3px}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojibtn:hover{-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;background-color:#e4e4e4;cursor:pointer}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojibtn i,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojibtn img{float:left;display:block;width:24px;height:24px}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojibtn img.lazy-emoji{filter:alpha(Opacity=0);opacity:0}.emojionearea .emojionearea-picker.emojionearea-filters-position-top .emojionearea-filters{top:0;-moz-border-radius-topleft:5px;-webkit-border-top-left-radius:5px;border-top-left-radius:5px;-moz-border-radius-topright:5px;-webkit-border-top-right-radius:5px;border-top-right-radius:5px}.emojionearea .emojionearea-picker.emojionearea-filters-position-top .emojionearea-scroll-area{bottom:0}.emojionearea .emojionearea-picker.emojionearea-filters-position-bottom .emojionearea-filters{bottom:0;-moz-border-radius-bottomleft:5px;-webkit-border-bottom-left-radius:5px;border-bottom-left-radius:5px;-moz-border-radius-bottomright:5px;-webkit-border-bottom-right-radius:5px;border-bottom-right-radius:5px}.emojionearea .emojionearea-picker.emojionearea-filters-position-bottom .emojionearea-scroll-area{top:0}.emojionearea .emojionearea-picker.emojionearea-picker-position-top{margin-top:-246px;right:-14px}.emojionearea .emojionearea-picker.emojionearea-picker-position-top .emojionearea-wrapper:after{width:19px;height:10px;background-position:-2px -49px;bottom:-10px;right:20px}.emojionearea .emojionearea-picker.emojionearea-picker-position-top.emojionearea-filters-position-bottom .emojionearea-wrapper:after{background-position:-2px -80px}.emojionearea .emojionearea-picker.emojionearea-picker-position-left,.emojionearea .emojionearea-picker.emojionearea-picker-position-right{margin-right:-326px;top:-8px}.emojionearea .emojionearea-picker.emojionearea-picker-position-left .emojionearea-wrapper:after,.emojionearea .emojionearea-picker.emojionearea-picker-position-right .emojionearea-wrapper:after{width:10px;height:19px;background-position:0 -60px;top:13px;left:-10px}.emojionearea .emojionearea-picker.emojionearea-picker-position-left.emojionearea-filters-position-bottom .emojionearea-wrapper:after,.emojionearea .emojionearea-picker.emojionearea-picker-position-right.emojionearea-filters-position-bottom .emojionearea-wrapper:after{background-position:right -60px}.emojionearea .emojionearea-picker.emojionearea-picker-position-bottom{margin-top:10px;right:-14px;top:47px}.emojionearea .emojionearea-picker.emojionearea-picker-position-bottom .emojionearea-wrapper:after{width:19px;height:10px;background-position:-2px -100px;top:-10px;right:20px}.emojionearea .emojionearea-picker.emojionearea-picker-position-bottom.emojionearea-filters-position-bottom .emojionearea-wrapper:after{background-position:-2px -90px}.emojionearea .emojionearea-button.active+.emojionearea-picker{filter:alpha(enabled=false);opacity:1}.emojionearea .emojionearea-button.active+.emojionearea-picker-position-top{margin-top:-229px}.emojionearea .emojionearea-button.active+.emojionearea-picker-position-left,.emojionearea .emojionearea-button.active+.emojionearea-picker-position-right{margin-right:-309px}.emojionearea .emojionearea-button.active+.emojionearea-picker-position-bottom{margin-top:-7px}.emojionearea.emojionearea-standalone{display:inline-block;width:auto;box-shadow:none}.emojionearea.emojionearea-standalone .emojionearea-editor{min-height:33px;position:relative;padding:6px 42px 6px 6px}.emojionearea.emojionearea-standalone .emojionearea-editor::before{content:"";position:absolute;top:4px;left:50%;bottom:4px;border-left:1px solid #e6e6e6}.emojionearea.emojionearea-standalone .emojionearea-editor.has-placeholder .emojioneemoji{opacity:.4}.emojionearea.emojionearea-standalone .emojionearea-button{top:0;right:0;bottom:0;left:0;width:auto;height:auto}.emojionearea.emojionearea-standalone .emojionearea-button>div{right:6px;top:5px}.emojionearea.emojionearea-standalone .emojionearea-picker.emojionearea-picker-position-bottom .emojionearea-wrapper:after,.emojionearea.emojionearea-standalone .emojionearea-picker.emojionearea-picker-position-top .emojionearea-wrapper:after{right:23px}.emojionearea.emojionearea-standalone .emojionearea-picker.emojionearea-picker-position-left .emojionearea-wrapper:after,.emojionearea.emojionearea-standalone .emojionearea-picker.emojionearea-picker-position-right .emojionearea-wrapper:after{top:15px}.emojionearea .emojionearea-button>div,.emojionearea .emojionearea-picker .emojionearea-wrapper:after{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAABuCAYAAADMB4ipAAAHfElEQVRo3u1XS1NT2Rb+9uOcQF4YlAJzLymFUHaLrdxKULvEUNpdTnRqD532f+AHMLMc94gqR1Zbt8rBnUh3YXipPGKwRDoWgXvrYiFUlEdIkPPYZ/dAkwox5yQCVt/bzRrBPnt9e+211/etFeDQDu3ArL+/X37OeqmRWoH7+vpItfWawStF1tfXR+zW9xW5ne0p8loOcAKuCdwpRft60C8a+X5zTvebCqcAvmidf1GGHtqhHdpf1qqKzsrKipyensbi4iKWl5cBAMFgEG1tbYhGo2hpadlbmxseHpaDg4MAgI6ODng8HgBAPp/H/Pw8AODatWvo7e2tvUHrui7v3r2L+fl5XL58GVeuXIHH49m1N5/Py0ePHmF0dBQdHR24desWVFXdtYdXAn/48CHm5+dx8+ZNRKPRigEUDpuenpb3799H4YaOnWh5eVmOj48jFoshGo0STdPkwMCAXF5elqV7BgYGpKZpMhqNklgshrGxMbx580Y6gicSCTDGEIvFAADpdBqpVArJZLK4J5lMIpVKIZ1OAwBisRgYY0gkEs6Rp1IphMNh+Hw+AgCGYQAANE0r7in8Xfjm8/lIOBzGq1evnMHX19fR1NRU/D8UCoFzjnA4XFwLh8PgnCMUChXXmpqakM1mUfVBS62xsZHk83lZWi1nz579ZA0AhBDO4A0NDchkMsWSJIRAURRiVy26rktVVUkmk0EgEHAGP3XqFKamppDP56Vpmrhz5w5u374t/X4/OP+w3TRNZLNZ6LoO0zSRz+dlf38/Ll686Jzz8+fPQwiBeDwOt9tNrl+/jkwmU6yaQpVkMhncuHEDbrebxONxCCEQiUScIw8Gg+TBgwdyZGQEyWRSdnV1kVQqJYeGhrC6ugrGGEKhEHp7e3Hy5EmSTCblvXv30NPTg2AwSA6M/vF4HCMjI7b0/yzh8vv9AIBsNrt34aokuQsLC7skt729varkHtqftUFf++FHsrq0QN3eBvp68Tfvf9Mv12oFCYU7G//e9nVuO7dpNbe2W4M//yQr0p8yRvyBo1Zr++lwLcCt7afD/sBRizJGavrB1dDYYh47Htrq+Kb7jBNwxzfdZ44dD201NLaYVUkU7ozQpuAJBkARwnRZpunN5zaa5hJjiXLH05GeiMd7JEM5zzHGNQBGZvk/Iv0yYVWMvK0zKk1Dl6ahW5RQobjqdjy+wEZn9PKF0n2d0csXPL7AhuKq26GECtPQLdPQZVtn1LlB69p7yRVVSEiDEGJwRd12e4+8PR3piRQidnuPvOWKuk0IMSSkwRVV6Np7WVVbSqvGsgSnlKkAFNPQXdrOtuKqcxtcUTUAhmUJnVJmlleJo3CVHmAaOlPUOmYJkxFKibQsSRkXhr4juKIKO2BHVSwcoLrqCVdUYho6K3YYRRWmoUtdey/tgKtK7rUffiQAsLq08MnbNLe2WwBgB/zHzueFyD8nwlIfbvdx8eU0WV1aKD1cVAMs9+F2j9gUPEEKemEJIe3AnXy4XfkBoNKSZHNthWfX31EA69VKttyHVyIOY1wRwmS6tqNsrr31vXo5k/bUu4gT2cp9lhbm0rzCJpeUUrE0vS63+c7/6uXMbDUWl/ssLczNFrVFddUT09AZpUy1LKvO0DVfPrfR9HxqfNbuEe185l9MFX3o6tIC5YpKFLWOfdQQ93Zu49j0+FDCDtjOp1yaOQCYhs4Y40wI05XfWj8yPT40Ua2ey33mEmMTtp2IUEq0nW3FKeJPGPjRp1Iz2QUuLUu66txG9NLVSK3gBZ+C1lcE54oqKOOCK6rm8QU2unu+u1ANuNynvFsBAG1ubbdMQ5eGviMAFDuP0w3sfMpvQEtb24fOQncU1bXl8R7JnOu+ZNv97XxKJwY6+PNPsrm13drObVqUMlMIU5OWpVHOc96Go5lTnV2fzC/VfAozD7HTCa6olBBa1Imlhbmq2lLuQ5xaW6nCPfnln0Yt7bDUhzhps8cfKH5//uTXmvS81OeLdqI/ZoROzSZrHqG/OvOPzxuhK5VgJTvV2bW3EdqJRABwrvvS/kfoSkoZvXT1YEbociHr7vnuYEfogpBFL109HKH/h0fomnXg3Lff79r7/MmvVbWG7gX4QObzc99+Tz7mHKah05KcW6ahQ9feS6cbMCdgt7eBWJagjCuUAC5tZzuouuo0Spm0hElc9R4cbf4bVl8v1p6WUmCuqEwIs34ruxaeeTy4uJVd67As08UVlVmWoG5vA7FLG3WMmHEupVTyW+vh2cn4DADMTsaTuc21LiGEhzHOnQ6gNtMrJSBMCKHkNt999WLi0S7hejEZH81n174WpukiIMw0dKq66p3Bw50RwhUVXFGJKUy28Xal48VkfKrSlWenhsc23q2cEB9SR7iiItwZIbbgHn8AlDFCCMW7laXjqZnHjkNpaubJzNuVpWZCKChjxOMPVH/QlaW0f/G3ZLqWWl6ce/bvlddp7yFD/w8Z+njoX1+GoZMjgzMAMDkyeLAMnRh+uKveJ0YGD4ahEyODFRk6OfrL/hj67GnckaHPng7vjaGzyYmaGDr77KktQ38H8tqx8Wja+WIAAAAASUVORK5CYII=)!important}.emojionearea.emojionearea-standalone .emojionearea-editor.has-placeholder{background-repeat:no-repeat;background-position:20px 4px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMAQMAAABsu86kAAAABlBMVEUAAAC/v79T5hyIAAAAAXRSTlMAQObYZgAAABNJREFUCNdjYGNgQEb/P4AQqiAASiUEG6Vit44AAAAASUVORK5CYII=)!important}
@@ -0,0 +1,50 @@
1
+ @import "https://fonts.googleapis.com/css?family=Lato:300&subset=latin-ext"
2
+
3
+ #chat .chat__header
4
+ font-family: 'Lato' !important
5
+ letter-spacing: 1.5px !important
6
+ height: 48px
7
+ background-color: #fff
8
+ box-shadow: 0px 2px 2px 0px rgba(0, 0, 0, 0.2)
9
+ display: flex
10
+ flex-direction: row
11
+ align-items: center
12
+ h6
13
+ font-family: 'Lato' !important
14
+ letter-spacing: 1.5px !important
15
+ margin: 0
16
+ font-weight: 300
17
+ font-size: 19px
18
+ i
19
+ margin: 0 10px 0 10px
20
+ color: #BDBDBD
21
+ transition: all .3s ease
22
+ cursor: pointer
23
+ &:hover
24
+ color: #212121
25
+
26
+ #chat .chat__badge
27
+ position: relative
28
+ #chat .chat__badge[data-badge]:after, .chat__launch.chat__badge[data-badge]:after
29
+ content: attr(data-badge)
30
+ display: flex
31
+ flex-direction: row
32
+ flex-wrap: wrap
33
+ justify-content: center
34
+ align-content: center
35
+ align-items: center
36
+ position: absolute
37
+ top: -7px
38
+ right: -10px
39
+ font-size: 12px
40
+ width: 22px
41
+ height: 22px
42
+ border-radius: 50%
43
+ background: #ff4081
44
+ color: #fff
45
+ font-family: 'Lato' !important
46
+ .chat__launch.chat__badge[data-badge]:after
47
+ position: fixed
48
+ bottom: 51px
49
+ right: 14px
50
+ top: initial
@@ -0,0 +1,26 @@
1
+ .chat__launch
2
+ position: fixed
3
+ right: 15px
4
+ bottom: 15px
5
+ border-radius: 50%
6
+ height: 56px
7
+ margin: auto
8
+ min-width: 56px
9
+ width: 56px
10
+ padding: 0
11
+ overflow: hidden
12
+ box-shadow: 0 1px 1.5px 0 rgba(0, 0, 0, 0.12), 0 1px 1px 0 rgba(0, 0, 0, 0.24)
13
+ line-height: normal
14
+ border: none
15
+ will-change: box-shadow
16
+ transition: box-shadow 0.2s cubic-bezier(0.4, 0, 1, 1), background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1), color 0.2s cubic-bezier(0.4, 0, 0.2, 1)
17
+ outline: none
18
+ cursor: pointer
19
+ text-decoration: none
20
+ i
21
+ position: fixed
22
+ right: 28px
23
+ bottom: 28px
24
+ font-size: 30px
25
+ &:active
26
+ box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.2)
@@ -0,0 +1,45 @@
1
+ @keyframes pulse
2
+ 50%
3
+ background-color: #C8E6C9
4
+
5
+ #chat .chat__list
6
+ height: calc(100% - 58px)
7
+ display: flex
8
+ flex-direction: column
9
+ padding-top: 10px
10
+ a
11
+ padding: 10px
12
+ text-align: center
13
+ transition: all 0.3s ease
14
+ text-decoration: none
15
+ color: #212121
16
+ &:hover
17
+ background: #BDBDBD
18
+ .chat__index
19
+ display: flex
20
+ flex-direction: column
21
+ overflow-y: auto
22
+ &::-webkit-scrollbar
23
+ display: none
24
+ .chat__has_new_message
25
+ animation: pulse 1s ease-out infinite
26
+
27
+ #chat .chat__start-new
28
+ font-weight: 300
29
+ border-top: 1px solid #BDBDBD
30
+ margin: 0 !important
31
+ font-size: 17px
32
+
33
+ #chat .chat__none-available
34
+ height: 100%
35
+ display: flex
36
+ flex-direction: column
37
+ align-items: center
38
+ justify-content: center
39
+ color: #bdbdbd
40
+ h5
41
+ font-weight: 400
42
+ font-size: 15px
43
+ margin: 5px 0px 5px 0px
44
+ i
45
+ font-size: 60px
@@ -0,0 +1,50 @@
1
+ @import "https://fonts.googleapis.com/css?family=Lato:300&subset=latin-ext"
2
+
3
+ #chat .new_message
4
+ margin: 0px 40px 36px 40px
5
+ flex-direction: column
6
+ display: flex
7
+ position: relative
8
+ .chat__insert-image
9
+ position: absolute
10
+ right: 28px
11
+ top: 4px
12
+ color: #bdbdbd
13
+ transition: all 0.3s ease
14
+ z-index: 10
15
+ cursor: pointer
16
+ font-size: 22px
17
+ &:hover
18
+ color: #212121
19
+ input[type='text'], textarea
20
+ font-size: 17px
21
+ font-family: "Lato" !important
22
+ letter-spacing: 1.5px !important
23
+ background: transparent
24
+ border: none
25
+ font-weight: 300
26
+ border-bottom: 1px solid rgba(0,0,0,.26)
27
+ height: 28px
28
+ outline: none
29
+ resize: none
30
+ .bar, .emojionearea-bar
31
+ position: relative
32
+ &:before, &:after
33
+ content: ''
34
+ height: 2px
35
+ width: 0
36
+ bottom: 0px
37
+ position: absolute
38
+ background: #3f51b5
39
+ transition: 0.2s ease all
40
+ -moz-transition: 0.2s ease all
41
+ -webkit-transition: 0.2s ease all
42
+ &:before
43
+ left: 50%
44
+ &:after
45
+ right: 50%
46
+ input[type='text']:focus ~ .bar:before, input[type='text']:focus ~ .bar:after,
47
+ textarea:focus ~ .bar:before, textarea:focus ~ .bar:after, .emojionearea-editor:focus ~ .emojionearea-bar:before, .emojionearea-editor:focus ~ .emojionearea-bar:after
48
+ width: 50%
49
+ input[type='file']
50
+ display: none !important
@@ -0,0 +1,53 @@
1
+ @import "https://fonts.googleapis.com/css?family=Lato:300&subset=latin-ext"
2
+
3
+ #chat .new_conversation
4
+ height: calc(100% - 48px)
5
+ display: none
6
+ flex-direction: column
7
+ .chat__user-check-boxes
8
+ margin: 10px 20px 0px 20px
9
+ display: flex
10
+ flex-direction: column
11
+ height: calc(100% - 48px)
12
+ overflow-y: auto
13
+ &::-webkit-scrollbar
14
+ display: none
15
+ label
16
+ position: relative
17
+ margin: 1rem
18
+ line-height: 135%
19
+ cursor: pointer
20
+ font-size: 18px
21
+ font-family: "Lato" !important
22
+ letter-spacing: 1.5px !important
23
+ padding-left: 40px
24
+ .chat__status
25
+ &:after
26
+ content: "\2022"
27
+ &.offline
28
+ &:after
29
+ color: #EF5350
30
+ &.online
31
+ &:after
32
+ color: #AED581
33
+
34
+ input[type='submit']
35
+ border-top: 1px solid #BDBDBD
36
+ border-left: none
37
+ border-bottom: none
38
+ border-right: none
39
+ font-family: "Lato" !important
40
+ letter-spacing: 1.5px !important
41
+ font-size: 17px
42
+ background: transparent
43
+ width: 100%
44
+ padding: 10px 0 10px 0
45
+ cursor: pointer
46
+ transition: all 0.3s ease
47
+ z-index: 10
48
+ &:hover
49
+ background: #BDBDBD
50
+
51
+ #chat .chat__errors
52
+ text-align: center
53
+ color: #F44336
@@ -0,0 +1,76 @@
1
+ #chat .current_chat
2
+ height: calc(100% - 48px)
3
+ flex-direction: column
4
+ img.chat__user-avatar
5
+ width: 50px
6
+ height: 50px
7
+ object-fit: cover
8
+ border-radius: 50%
9
+ i.chat__user-avatar
10
+ font-size: 50px
11
+ .chat__transcript
12
+ max-height: calc(100% - 78px)
13
+ overflow-y: auto
14
+ &::-webkit-scrollbar
15
+ display: none
16
+ .chat__image-message
17
+ width: 100%
18
+ padding-top: 10px
19
+ padding-bottom: 10px
20
+ img
21
+ width: 100%
22
+ border-bottom: 4px solid #C8E6C9
23
+ &.current img
24
+ border-bottom: 4px solid #B2EBF2
25
+ .chat__message
26
+ padding: 10px
27
+ display: flex
28
+ flex-direction: row
29
+ img
30
+ font-size: inherit
31
+ height: 2ex
32
+ width: 2.1ex
33
+ min-height: 20px
34
+ min-width: 20px
35
+ display: inline-block
36
+ margin: -.2ex .15em .2ex
37
+ line-height: normal
38
+ vertical-align: middle
39
+ max-width: 100%
40
+ top: 0
41
+ .text
42
+ padding: 5px
43
+ flex: 1
44
+ position: relative
45
+ &.right
46
+ margin-right: 10px
47
+ border-radius: 5px 0px 5px 5px
48
+ background: #B2EBF2
49
+ border: none
50
+ &:after
51
+ content: ""
52
+ position: absolute
53
+ border-style: solid
54
+ border-width: 0px 0 13px 15px
55
+ border-color: transparent #B2EBF2
56
+ display: block
57
+ width: 0
58
+ z-index: 1
59
+ right: -15px
60
+ top: 0px
61
+ &.left
62
+ margin-left: 10px
63
+ border-radius: 0px 5px 5px 5px
64
+ background: #C8E6C9
65
+ border: none
66
+ &:after
67
+ content: ""
68
+ position: absolute
69
+ border-style: solid
70
+ border-width: 0px 15px 13px 0px
71
+ border-color: transparent #C8E6C9
72
+ display: block
73
+ width: 0
74
+ z-index: 1
75
+ left: -15px
76
+ top: 0px
@@ -0,0 +1,11 @@
1
+ class Chat::MessagesChannel < ApplicationCable::Channel
2
+ def follow(data)
3
+ stop_all_streams
4
+ stream_from "chats::#{data['chat_id']}::messages"
5
+ end
6
+
7
+ def unfollow
8
+ stop_all_streams
9
+ end
10
+ alias unsubscribed unfollow
11
+ end
@@ -0,0 +1,10 @@
1
+ class Chat::NotificationChannel < ApplicationCable::Channel
2
+ def follow(data)
3
+ stop_all_streams
4
+ stream_from "users::#{data['user_id']}::chats"
5
+ end
6
+
7
+ def unsubscribed
8
+ stop_all_streams
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ class Chat::StatusChannel < ApplicationCable::Channel
2
+ def online
3
+ stop_all_streams
4
+ stream_from "chat::status"
5
+ current_user.online
6
+ end
7
+
8
+ def unsubscribed
9
+ current_user.offline
10
+ stop_all_streams
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ module Chat
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+ end
5
+ end
@@ -0,0 +1,30 @@
1
+ module Chat
2
+ class ConversationsController < ApplicationController
3
+ before_action Chat.logged_in_check
4
+ before_action :set_conversation, only: :show
5
+
6
+ def show
7
+ end
8
+
9
+ def create
10
+ @conversation = Chat::Conversation.create(conversation_params)
11
+ end
12
+
13
+ private
14
+
15
+ def set_conversation
16
+ @conversation = Chat::Conversation.includes(
17
+ :users, messages: :user
18
+ ).find(params[:id])
19
+ end
20
+
21
+ def conversation_params
22
+ chat_params = params.require(:conversation).permit(user_ids: [])
23
+ if chat_params[:user_ids].reject(&:blank?).present?
24
+ chat_params[:user_ids] << current_user.id
25
+ end
26
+
27
+ chat_params
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,28 @@
1
+ module Chat
2
+ class MessagesController < ApplicationController
3
+ before_action Chat.logged_in_check
4
+ before_action :set_conversation
5
+
6
+ def create
7
+ @conversation.messages.create(message_params)
8
+
9
+ head :ok
10
+ end
11
+
12
+ def destroy
13
+ @conversation.destroy
14
+ end
15
+
16
+ private
17
+
18
+ def set_conversation
19
+ @conversation = Chat::Conversation.find(params[:conversation_id])
20
+ end
21
+
22
+ def message_params
23
+ params.require(:message).permit(:text, :image).merge(
24
+ user_id: current_user.id
25
+ )
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,62 @@
1
+ module Chat
2
+ module ApplicationHelper
3
+ def render_chat(background = nil, color = nil)
4
+ return unless send Chat.signed_in
5
+
6
+ render "chat/chat", background: background, color: color
7
+ end
8
+
9
+ def launch_chat_fab(background = "#4CAF50", color = "light")
10
+ attrs = {
11
+ class: "chat__launch", style: "background: #{background}",
12
+ data: { "current-user" => current_user.id }
13
+ }
14
+ button_tag(attrs) do
15
+ material_icon.forum.css_class("md-#{color}").to_s.html_safe
16
+ end
17
+ end
18
+
19
+ def chatable_users
20
+ @chatable_users ||= ::User.where.not(id: current_user.id)
21
+ end
22
+
23
+ def chatable_user_check_boxes(f)
24
+ f.collection_check_boxes(:user_ids, chatable_users, :id, :name) do |b|
25
+ b.check_box + b.label(class: b.object.chat_status) do
26
+ content_tag(
27
+ :div, b.text,
28
+ class: "chat__status #{b.object.chat_status}"
29
+ )
30
+ end
31
+ end
32
+ end
33
+
34
+ def chat_avatar(user)
35
+ if user.send(Chat.user_avatar.to_s + "?")
36
+ image_tag(user.send(Chat.user_avatar), class: "chat__user-avatar")
37
+ else
38
+ MaterialIcon.new.css_class("chat__user-avatar").person
39
+ end
40
+ end
41
+
42
+ def chat_list
43
+ @chat_list ||=
44
+ Chat::Conversation.joins(:users)
45
+ .group("chat_sessions.conversation_id")
46
+ .select(:id, group_concat)
47
+ .merge(current_user.conversations)
48
+ .order(created_at: :desc)
49
+ end
50
+
51
+ private
52
+
53
+ def group_concat
54
+ if ActiveRecord::Base.connection.adapter_name == "SQLite"
55
+ "GROUP_CONCAT(users.#{::User.first_name} || ' ' || users.#{::User.last_name}, ', ') as names"
56
+ elsif ActiveRecord::Base.connection.adapter_name == "MySQL"
57
+ "GROUP_CONCAT(CONCAT(\"users.#{User.first_name}\",\" \", \"users.#{User.last_name}\") "\
58
+ "SEPARATOR ', ') as names"
59
+ end
60
+ end
61
+ end
62
+ end