diff --git a/.gitignore b/.gitignore
index 8434f39..aed3396 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,5 @@
/config/oauth.yml
bundle/
+public/images/emoji
+vendor/assets/bower_components
diff --git a/Bowerfile b/Bowerfile
new file mode 100644
index 0000000..1c38b5d
--- /dev/null
+++ b/Bowerfile
@@ -0,0 +1 @@
+asset 'jquery-textcomplete'
diff --git a/Gemfile b/Gemfile
index d07e45f..cf8b7e1 100644
--- a/Gemfile
+++ b/Gemfile
@@ -11,6 +11,8 @@ gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.1.0'
gem 'turbolinks'
+gem 'bower-rails'
+gem 'gon'
gem 'jquery-rails'
gem 'bourbon'
@@ -26,6 +28,7 @@ gem 'jbuilder', '~> 2.2.12'
gem 'yajl-ruby', '~> 1.2.1'
gem 'github-markdown', '~> 0.6.8'
gem 'redcarpet', '~> 3.3.1'
+gem 'gemoji'
gem 'omniauth', '~> 1.2.2'
gem 'omniauth-slack', '~> 2.0.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 314c7b4..7f0ef39 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -47,6 +47,7 @@ GEM
bourbon (4.2.3)
sass (~> 3.4)
thor
+ bower-rails (0.10.0)
builder (3.2.2)
bullet (4.14.7)
activesupport (>= 3.0.0)
@@ -91,9 +92,15 @@ GEM
multipart-post (>= 1.2, < 3)
font-awesome-sass (4.3.2.1)
sass (~> 3.2)
+ gemoji (2.1.0)
github-markdown (0.6.8)
globalid (0.3.5)
activesupport (>= 4.1.0)
+ gon (6.0.1)
+ actionpack (>= 3.0)
+ json
+ multi_json
+ request_store (>= 1.0)
haml (4.0.6)
tilt
haml-rails (0.9.0)
@@ -205,6 +212,7 @@ GEM
rake (10.4.2)
redcarpet (3.3.1)
ref (1.0.5)
+ request_store (1.2.0)
rsolr (1.0.12)
builder (>= 2.1.2)
rspec-core (3.2.3)
@@ -281,6 +289,7 @@ DEPENDENCIES
better_errors (= 2.1.1)
binding_of_caller (= 0.7.2)
bourbon
+ bower-rails
bullet
byebug
capistrano (= 3.4.0)
@@ -291,7 +300,9 @@ DEPENDENCIES
coffee-rails (~> 4.1.0)
factory_girl_rails (~> 4.5.0)
font-awesome-sass (~> 4.3.0)
+ gemoji
github-markdown (~> 0.6.8)
+ gon
haml-rails (~> 0.9.0)
jbuilder (~> 2.2.12)
jquery-rails
@@ -320,3 +331,6 @@ DEPENDENCIES
unicorn (= 4.8.3)
web-console (~> 2.0)
yajl-ruby (~> 1.2.1)
+
+BUNDLED WITH
+ 1.10.6
diff --git a/README.md b/README.md
index 34a8485..beb6e77 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@ RG Portal
* Ruby 2.2.1
* Bundler
+* Bower
### Recommends
@@ -23,7 +24,7 @@ $ cp config/oauth.yml.sample config/oauth.yml
* Do not create a new authentication yourself. The number of integrations has a limit.
-### Library installation
+### Gem installation
```
$ bundle install --path=vendor/bundle
@@ -36,6 +37,18 @@ $ bundle config build.libv8 --with-system-v8
$ bundle config build.therubyracer --with-v8-dir
```
+### Copy emoji files to public directory
+
+```
+$ rake emoji
+```
+
+### JavaScript library installation
+
+```
+rake bower:install
+```
+
### Database creation
```
diff --git a/Rakefile b/Rakefile
index ba6b733..6a66787 100644
--- a/Rakefile
+++ b/Rakefile
@@ -4,3 +4,5 @@
require File.expand_path('../config/application', __FILE__)
Rails.application.load_tasks
+
+load 'tasks/emoji.rake'
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 788c662..c6f2d0b 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -14,4 +14,5 @@
//= require jquery_ujs
//= require jquery_nested_form
//= require turbolinks
+//= require jquery-textcomplete/dist/jquery.textcomplete
//= require_tree .
diff --git a/app/assets/javascripts/emoji_complete.js.coffee b/app/assets/javascripts/emoji_complete.js.coffee
new file mode 100644
index 0000000..988b5a5
--- /dev/null
+++ b/app/assets/javascripts/emoji_complete.js.coffee
@@ -0,0 +1,16 @@
+ready = ->
+ emojiCompletions = $('textarea.emoji-complete')
+ if emojiCompletions.length > 0
+ emojiAliases = Object.keys(gon.emojis)
+ emojiCompletions.textcomplete([
+ match: /(^|\s):([\w+-]*)$/,
+ search: (term, callback) ->
+ callback(emojiAliases.filter (e) -> e.indexOf(term) != -1)
+ template: (value) ->
+ " #{value}"
+ replace: (value) ->
+ "$1:#{value}:"
+ ], maxCount: 5)
+
+$(ready)
+$(document).on('page:load', ready)
diff --git a/app/assets/stylesheets/_style.css.scss b/app/assets/stylesheets/_style.css.scss
index e361495..4ce5f25 100644
--- a/app/assets/stylesheets/_style.css.scss
+++ b/app/assets/stylesheets/_style.css.scss
@@ -109,3 +109,10 @@ nav {
width: 15%;
}
}
+
+.emoji {
+ width: 1em;
+ height: 1em;
+ margin: 0;
+ padding: 0;
+}
diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss
index 32db6da..26ff702 100644
--- a/app/assets/stylesheets/application.css.scss
+++ b/app/assets/stylesheets/application.css.scss
@@ -1,6 +1,9 @@
// Reset CSS
@import "reset";
+// Autocomplete
+@import "jquery-textcomplete/dist/jquery.textcomplete.css";
+
// Bootstrap
@import "bourbon";
@import "neat";
diff --git a/app/controllers/concerns/emoji_complete.rb b/app/controllers/concerns/emoji_complete.rb
new file mode 100644
index 0000000..b45320a
--- /dev/null
+++ b/app/controllers/concerns/emoji_complete.rb
@@ -0,0 +1,5 @@
+module EmojiComplete
+ def set_emoji_completion
+ gon.emojis = Emoji.send(:names_index).map { |name, emoji| [name, emoji.image_filename] }.to_h
+ end
+end
diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb
index 614a452..8822323 100644
--- a/app/controllers/pages_controller.rb
+++ b/app/controllers/pages_controller.rb
@@ -1,7 +1,9 @@
class PagesController < ApplicationController
+ include EmojiComplete
before_action :require_active_current_user
before_action :set_page, only: [:show, :edit, :update]
before_action :set_new_comment, only: :show
+ before_action :set_emoji_completion, only: [:show, :edit]
def index
@pages = Page.all
diff --git a/app/models/comment.rb b/app/models/comment.rb
index 555743b..bd15833 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -1,4 +1,7 @@
class Comment < ActiveRecord::Base
+ include Emojifier
+ include MarkdownRender
+
belongs_to :user
belongs_to :page
@@ -8,10 +11,6 @@ class Comment < ActiveRecord::Base
MENTION_USER_REGEX = /@[A-z0-9]+/
- def render_content
- Redcarpet::Markdown.new(Redcarpet::Render::HTML).render(self.content)
- end
-
private
def notify_mentions
diff --git a/app/models/concerns/emojifier.rb b/app/models/concerns/emojifier.rb
new file mode 100644
index 0000000..36c53c5
--- /dev/null
+++ b/app/models/concerns/emojifier.rb
@@ -0,0 +1,13 @@
+module Emojifier
+ def emojify
+ self.content.gsub(/:([\w+-]+):/) do |match|
+ name = Regexp.last_match(1)
+ emoji = Emoji.find_by_alias(name)
+ return match unless emoji
+ ActionController::Base.helpers.image_tag(
+ ActionController::Base.helpers.image_path("emoji/#{emoji.image_filename}"),
+ alt: name, class: 'emoji'
+ )
+ end
+ end
+end
diff --git a/app/models/concerns/markdown_render.rb b/app/models/concerns/markdown_render.rb
index 4f764ca..fef260f 100644
--- a/app/models/concerns/markdown_render.rb
+++ b/app/models/concerns/markdown_render.rb
@@ -3,6 +3,7 @@ module MarkdownRender
HTML_RENDER_OPTIONS = { hard_wrap: true }
def render_content
- Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(HTML_RENDER_OPTIONS), MARKDOWN_RENDER_OPTIONS).render(self.content)
+ content = self.class.include?(Emojifier) ? emojify : self.content
+ Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(HTML_RENDER_OPTIONS), MARKDOWN_RENDER_OPTIONS).render(content)
end
end
diff --git a/app/models/page.rb b/app/models/page.rb
index b6ef30b..077a7a1 100644
--- a/app/models/page.rb
+++ b/app/models/page.rb
@@ -1,4 +1,5 @@
class Page < ActiveRecord::Base
+ include Emojifier
include MarkdownRender
has_many :comments
diff --git a/app/views/comments/_list.html.haml b/app/views/comments/_list.html.haml
index 11a5164..4c82b03 100644
--- a/app/views/comments/_list.html.haml
+++ b/app/views/comments/_list.html.haml
@@ -16,5 +16,5 @@
.user
.icon= image_tag @current_user.icon_url
.box
- = f.text_area :content, rows: 4
+ = f.text_area :content, rows: 4, class: 'emoji-complete'
= f.submit 'Comment'
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index 82085a9..7ea23b6 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -6,6 +6,7 @@
= content_for(:css)
= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true
= content_for(:javascript)
+ = include_gon
= javascript_include_tag 'application', 'data-turbolinks-track' => true
= csrf_meta_tags
%body
diff --git a/app/views/pages/edit.html.haml b/app/views/pages/edit.html.haml
index 8db5297..cef6385 100644
--- a/app/views/pages/edit.html.haml
+++ b/app/views/pages/edit.html.haml
@@ -3,7 +3,7 @@
= form_for @page, url: update_page_path, method: :patch do |f|
= f.hidden_field :path
= f.text_field :title
- = f.text_area :content, rows: 30
+ = f.text_area :content, rows: 30, class: 'emoji-complete'
= f.submit 'Save'
= f.submit 'Draft Save', name: 'draft'
= link_to 'Cancel', page_path(@page.path)
diff --git a/config/deploy.rb b/config/deploy.rb
index b2ef2ab..a335eff 100644
--- a/config/deploy.rb
+++ b/config/deploy.rb
@@ -20,3 +20,25 @@
invoke 'unicorn:restart'
end
end
+
+before 'deploy:compile_assets', 'bower:install'
+namespace :bower do
+ task :install do
+ on roles(:web) do
+ within release_path do
+ execute :rake, 'bower:install CI=true'
+ end
+ end
+ end
+end
+
+before 'deploy:compile_assets', 'gemoji:install'
+namespace :gemoji do
+ task :install do
+ on roles(:web) do
+ within release_path do
+ execute :rake, 'gemoji'
+ end
+ end
+ end
+end
diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb
index 1ae31fd..e54f596 100644
--- a/config/initializers/assets.rb
+++ b/config/initializers/assets.rb
@@ -4,8 +4,11 @@
Rails.application.config.assets.version = '1.0'
# Add additional assets to the asset load path
-# Rails.application.config.assets.paths << Emoji.images_path
+Rails.application.config.assets.paths << Emoji.images_path
+Rails.application.config.assets.paths << Rails.root.join('vendor', 'assets', 'bower_components')
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
# Rails.application.config.assets.precompile += %w(*.css *.scss)
+Rails.application.config.assets.precompile += %w(emoji/*.png)
+Rails.application.config.assets.precompile += %w(emoji/**/*.png)
diff --git a/config/initializers/bower_rails.rb b/config/initializers/bower_rails.rb
new file mode 100644
index 0000000..8b5d67f
--- /dev/null
+++ b/config/initializers/bower_rails.rb
@@ -0,0 +1,19 @@
+BowerRails.configure do |bower_rails|
+ # Tell bower-rails what path should be considered as root. Defaults to Dir.pwd
+ # bower_rails.root_path = Dir.pwd
+
+ # Invokes rake bower:install before precompilation. Defaults to false
+ bower_rails.install_before_precompile = true
+
+ # Invokes rake bower:resolve before precompilation. Defaults to false
+ # bower_rails.resolve_before_precompile = true
+
+ # Invokes rake bower:clean before precompilation. Defaults to false
+ bower_rails.clean_before_precompile = true
+
+ # Invokes rake bower:install:deployment instead rake bower:install. Defaults to false
+ # bower_rails.use_bower_install_deployment = true
+ #
+ # Invokes rake bower:install and rake bower:install:deployment with -F (force) flag. Defaults to false
+ # bower_rails.force_install = true
+end
diff --git a/spec/factories/comments.rb b/spec/factories/comments.rb
index 2c5c395..d9064c4 100644
--- a/spec/factories/comments.rb
+++ b/spec/factories/comments.rb
@@ -1,8 +1,7 @@
FactoryGirl.define do
factory :comment do
- user nil
-post nil
-content "MyText"
+ content 'This is a comment.'
+ association :user
+ association :page
end
-
end
diff --git a/spec/factories/pages.rb b/spec/factories/pages.rb
new file mode 100644
index 0000000..03d422a
--- /dev/null
+++ b/spec/factories/pages.rb
@@ -0,0 +1,7 @@
+FactoryGirl.define do
+ factory :page do
+ path 'sample'
+ title 'sample'
+ content 'This is a page.'
+ end
+end
diff --git a/spec/factories/slack_credentials.rb b/spec/factories/slack_credentials.rb
index 28faa92..ca50f7d 100644
--- a/spec/factories/slack_credentials.rb
+++ b/spec/factories/slack_credentials.rb
@@ -1,5 +1,5 @@
FactoryGirl.define do
factory :slack_credential do
- user_id 'U03AE1H0U'
+ sequence(:slack_user_id) { |n| "U03AE1H0U#{n}" }
end
end
diff --git a/spec/models/comment_spec.rb b/spec/models/comment_spec.rb
index c10688d..7151c3e 100644
--- a/spec/models/comment_spec.rb
+++ b/spec/models/comment_spec.rb
@@ -1,5 +1,5 @@
require 'rails_helper'
RSpec.describe Comment, type: :model do
- pending "add some examples to (or delete) #{__FILE__}"
+ it_behaves_like 'emojifier'
end
diff --git a/spec/models/concerns/emojifier.rb b/spec/models/concerns/emojifier.rb
new file mode 100644
index 0000000..ab1cae9
--- /dev/null
+++ b/spec/models/concerns/emojifier.rb
@@ -0,0 +1,20 @@
+require 'rails_helper'
+
+shared_examples_for 'emojifier' do
+ let(:model) { described_class }
+ let(:factory) { model.to_s.underscore.to_sym }
+
+ subject { object.emojify }
+
+ context 'contents do not include any emojis' do
+ let(:object) { FactoryGirl.create(factory, content: 'Example content') }
+ it { should eq(object.content) }
+ end
+
+ context 'contents include some emojis' do
+ let(:object) { FactoryGirl.create(factory, content: 'Example content :smile: :+1:') }
+
+ it { should_not match(/:[\w+-]+:/) }
+ it { should match(/