Commit ad76c651 by tady

Merge pull request #83 from tadyjp/140420/update_tag_page

[WIP] タグページレイアウト変更
parents ea703555 abd2c16f
...@@ -30,3 +30,5 @@ ...@@ -30,3 +30,5 @@
/backup /backup
/script/backup.sh /script/backup.sh
.rbenv-gemsets
...@@ -24,4 +24,4 @@ before_script: ...@@ -24,4 +24,4 @@ before_script:
- cp config/settings.yml.example config/settings.yml - cp config/settings.yml.example config/settings.yml
after_script: after_script:
- ruby script/travis/bundle_cache.rb - ruby script/travis/bundle_cache.rb
script: bundle exec rake db:create db:test:load spec script: bundle exec rake db:create db:test:load spec teaspoon
...@@ -50,6 +50,9 @@ gem 'mysql2' ...@@ -50,6 +50,9 @@ gem 'mysql2'
gem 'devise' gem 'devise'
# http://d.hatena.ne.jp/tkawa/20130812/p1
gem 'devise-better_routes'
gem 'omniauth-google-oauth2' gem 'omniauth-google-oauth2'
# Markdown # Markdown
...@@ -68,7 +71,7 @@ group :development do ...@@ -68,7 +71,7 @@ group :development do
gem 'pry-rails' gem 'pry-rails'
# profiler # profiler
# gem 'rack-mini-profiler' gem 'rack-mini-profiler'
# rubocop # rubocop
gem 'rubocop' gem 'rubocop'
...@@ -89,6 +92,9 @@ group :development, :test do ...@@ -89,6 +92,9 @@ group :development, :test do
# gem 'database_cleaner' # gem 'database_cleaner'
gem 'database_rewinder' gem 'database_rewinder'
gem 'teaspoon'
gem 'guard-teaspoon'
end end
group :test do group :test do
...@@ -132,3 +138,5 @@ gem 'newrelic_rpm' ...@@ -132,3 +138,5 @@ gem 'newrelic_rpm'
gem 'breadcrumble' gem 'breadcrumble'
gem 'slim' gem 'slim'
gem 'annotate', ">=2.6.0"
...@@ -10,36 +10,40 @@ GIT ...@@ -10,36 +10,40 @@ GIT
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actionmailer (4.0.4) actionmailer (4.1.0)
actionpack (= 4.0.4) actionpack (= 4.1.0)
actionview (= 4.1.0)
mail (~> 2.5.4) mail (~> 2.5.4)
actionpack (4.0.4) actionpack (4.1.0)
activesupport (= 4.0.4) actionview (= 4.1.0)
builder (~> 3.1.0) activesupport (= 4.1.0)
erubis (~> 2.7.0)
rack (~> 1.5.2) rack (~> 1.5.2)
rack-test (~> 0.6.2) rack-test (~> 0.6.2)
activemodel (4.0.4) actionview (4.1.0)
activesupport (= 4.0.4) activesupport (= 4.1.0)
builder (~> 3.1.0) builder (~> 3.1)
activerecord (4.0.4) erubis (~> 2.7.0)
activemodel (= 4.0.4) activemodel (4.1.0)
activerecord-deprecated_finders (~> 1.0.2) activesupport (= 4.1.0)
activesupport (= 4.0.4) builder (~> 3.1)
arel (~> 4.0.0) activerecord (4.1.0)
activerecord-deprecated_finders (1.0.3) activemodel (= 4.1.0)
activesupport (4.0.4) activesupport (= 4.1.0)
arel (~> 5.0.0)
activesupport (4.1.0)
i18n (~> 0.6, >= 0.6.9) i18n (~> 0.6, >= 0.6.9)
minitest (~> 4.2) json (~> 1.7, >= 1.7.7)
multi_json (~> 1.3) minitest (~> 5.1)
thread_safe (~> 0.1) thread_safe (~> 0.1)
tzinfo (~> 0.3.37) tzinfo (~> 1.1)
addressable (2.3.6) addressable (2.3.6)
ancestry (2.0.0) ancestry (2.1.0)
activerecord (>= 3.0.0) activerecord (>= 3.0.0)
arel (4.0.2) annotate (2.6.3)
activerecord (>= 2.3.0)
rake (>= 0.8.7)
arel (5.0.1.20140414130214)
ast (1.1.0) ast (1.1.0)
atomic (1.1.16)
aws-sdk (1.38.0) aws-sdk (1.38.0)
json (~> 1.4) json (~> 1.4)
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
...@@ -52,8 +56,8 @@ GEM ...@@ -52,8 +56,8 @@ GEM
debug_inspector (>= 0.0.1) debug_inspector (>= 0.0.1)
breadcrumble (4.0.0) breadcrumble (4.0.0)
rails (>= 4.0.0) rails (>= 4.0.0)
builder (3.1.4) builder (3.2.2)
capistrano (3.1.0) capistrano (3.2.0)
i18n i18n
rake (>= 10.0.0) rake (>= 10.0.0)
sshkit (~> 1.3) sshkit (~> 1.3)
...@@ -103,6 +107,9 @@ GEM ...@@ -103,6 +107,9 @@ GEM
railties (>= 3.2.6, < 5) railties (>= 3.2.6, < 5)
thread_safe (~> 0.1) thread_safe (~> 0.1)
warden (~> 1.2.3) warden (~> 1.2.3)
devise-better_routes (0.0.4)
devise (>= 3.0.0.rc)
rails (>= 4.0.0.rc1)
diff-lcs (1.2.5) diff-lcs (1.2.5)
docile (1.1.3) docile (1.1.3)
domain_name (0.5.18) domain_name (0.5.18)
...@@ -138,10 +145,13 @@ GEM ...@@ -138,10 +145,13 @@ GEM
guard-rspec (4.2.8) guard-rspec (4.2.8)
guard (~> 2.1) guard (~> 2.1)
rspec (>= 2.14, < 4.0) rspec (>= 2.14, < 4.0)
guard-rubocop (1.0.2) guard-rubocop (1.1.0)
guard (~> 2.0) guard (~> 2.0)
rubocop (~> 0.10) rubocop (~> 0.20)
hashie (2.0.5) guard-teaspoon (0.0.4)
guard (>= 1.6.1)
teaspoon (>= 0.5.3)
hashie (2.1.1)
hike (1.2.3) hike (1.2.3)
htmlentities (4.3.1) htmlentities (4.3.1)
http-cookie (1.0.2) http-cookie (1.0.2)
...@@ -150,9 +160,9 @@ GEM ...@@ -150,9 +160,9 @@ GEM
i18n_generators (1.2.1) i18n_generators (1.2.1)
mechanize mechanize
rails (>= 3.0.0) rails (>= 3.0.0)
jbuilder (2.0.5) jbuilder (2.0.6)
activesupport (>= 3.0.0) activesupport (>= 3.0.0, < 5)
multi_json (>= 1.2.0) multi_json (~> 1.2)
jquery-rails (3.1.0) jquery-rails (3.1.0)
railties (>= 3.0, < 5.0) railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0) thor (>= 0.14, < 2.0)
...@@ -183,14 +193,14 @@ GEM ...@@ -183,14 +193,14 @@ GEM
method_source (0.8.2) method_source (0.8.2)
mime-types (1.25.1) mime-types (1.25.1)
mini_portile (0.5.3) mini_portile (0.5.3)
minitest (4.7.5) minitest (5.3.3)
multi_json (1.9.2) multi_json (1.9.2)
multi_xml (0.5.5) multi_xml (0.5.5)
multipart-post (2.0.0) multipart-post (2.0.0)
mysql2 (0.3.15) mysql2 (0.3.15)
net-http-digest_auth (1.4) net-http-digest_auth (1.4)
net-http-persistent (2.9.4) net-http-persistent (2.9.4)
net-scp (1.1.2) net-scp (1.2.0)
net-ssh (>= 2.6.5) net-ssh (>= 2.6.5)
net-ssh (2.8.0) net-ssh (2.8.0)
newrelic_rpm (3.7.3.204) newrelic_rpm (3.7.3.204)
...@@ -208,9 +218,9 @@ GEM ...@@ -208,9 +218,9 @@ GEM
omniauth (1.2.1) omniauth (1.2.1)
hashie (>= 1.2, < 3) hashie (>= 1.2, < 3)
rack (~> 1.0) rack (~> 1.0)
omniauth-google-oauth2 (0.2.2) omniauth-google-oauth2 (0.2.3)
omniauth (~> 1.0) omniauth (~> 1.0)
omniauth-oauth2 omniauth-oauth2 (~> 1.1)
omniauth-oauth2 (1.1.2) omniauth-oauth2 (1.1.2)
faraday (>= 0.8, < 0.10) faraday (>= 0.8, < 0.10)
multi_json (~> 1.3) multi_json (~> 1.3)
...@@ -220,7 +230,7 @@ GEM ...@@ -220,7 +230,7 @@ GEM
paper_trail (3.0.1) paper_trail (3.0.1)
activerecord (>= 3.0, < 5.0) activerecord (>= 3.0, < 5.0)
activesupport (>= 3.0, < 5.0) activesupport (>= 3.0, < 5.0)
parser (2.1.7) parser (2.1.8)
ast (~> 1.1) ast (~> 1.1)
slop (~> 3.4, >= 3.4.5) slop (~> 3.4, >= 3.4.5)
poltergeist (1.5.0) poltergeist (1.5.0)
...@@ -240,23 +250,27 @@ GEM ...@@ -240,23 +250,27 @@ GEM
pry-rails (0.3.2) pry-rails (0.3.2)
pry (>= 0.9.10) pry (>= 0.9.10)
rack (1.5.2) rack (1.5.2)
rack-mini-profiler (0.9.0)
rack (>= 1.1.3)
rack-test (0.6.2) rack-test (0.6.2)
rack (>= 1.0) rack (>= 1.0)
rails (4.0.4) rails (4.1.0)
actionmailer (= 4.0.4) actionmailer (= 4.1.0)
actionpack (= 4.0.4) actionpack (= 4.1.0)
activerecord (= 4.0.4) actionview (= 4.1.0)
activesupport (= 4.0.4) activemodel (= 4.1.0)
activerecord (= 4.1.0)
activesupport (= 4.1.0)
bundler (>= 1.3.0, < 2.0) bundler (>= 1.3.0, < 2.0)
railties (= 4.0.4) railties (= 4.1.0)
sprockets-rails (~> 2.0.0) sprockets-rails (~> 2.0)
railties (4.0.4) railties (4.1.0)
actionpack (= 4.0.4) actionpack (= 4.1.0)
activesupport (= 4.0.4) activesupport (= 4.1.0)
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rainbow (2.0.0) rainbow (2.0.0)
rake (10.2.1) rake (10.3.1)
rb-fsevent (0.9.4) rb-fsevent (0.9.4)
rb-inotify (0.9.3) rb-inotify (0.9.3)
ffi (>= 0.5.0) ffi (>= 0.5.0)
...@@ -282,18 +296,19 @@ GEM ...@@ -282,18 +296,19 @@ GEM
rspec-core (~> 2.14.0) rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0) rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0) rspec-mocks (~> 2.14.0)
rubocop (0.19.1) rubocop (0.20.1)
json (>= 1.7.7, < 2) json (>= 1.7.7, < 2)
parser (~> 2.1.7) parser (~> 2.1.7)
powerpack (~> 0.0.6) powerpack (~> 0.0.6)
rainbow (>= 1.99.1, < 3.0) rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.4) ruby-progressbar (~> 1.4)
ruby-progressbar (1.4.2) ruby-progressbar (1.4.2)
sass (3.3.4) sass (3.2.19)
sass-rails (4.0.1) sass-rails (4.0.3)
railties (>= 4.0.0, < 5.0) railties (>= 4.0.0, < 5.0)
sass (>= 3.1.10) sass (~> 3.2.0)
sprockets-rails (~> 2.0.0) sprockets (~> 2.8, <= 2.11.0)
sprockets-rails (~> 2.0)
sdoc (0.4.0) sdoc (0.4.0)
json (~> 1.8) json (~> 1.8)
rdoc (~> 4.0, < 5.0) rdoc (~> 4.0, < 5.0)
...@@ -307,19 +322,21 @@ GEM ...@@ -307,19 +322,21 @@ GEM
temple (~> 0.6.6) temple (~> 0.6.6)
tilt (>= 1.3.3, < 2.1) tilt (>= 1.3.3, < 2.1)
slop (3.5.0) slop (3.5.0)
sprockets (2.12.0) sprockets (2.11.0)
hike (~> 1.2) hike (~> 1.2)
multi_json (~> 1.0) multi_json (~> 1.0)
rack (~> 1.0) rack (~> 1.0)
tilt (~> 1.1, != 1.3.0) tilt (~> 1.1, != 1.3.0)
sprockets-rails (2.0.1) sprockets-rails (2.1.3)
actionpack (>= 3.0) actionpack (>= 3.0)
activesupport (>= 3.0) activesupport (>= 3.0)
sprockets (~> 2.8) sprockets (~> 2.8)
sshkit (1.3.0) sshkit (1.4.0)
net-scp (>= 1.1.2) net-scp (>= 1.1.2)
net-ssh net-ssh (>= 2.8.0)
term-ansicolor term-ansicolor
teaspoon (0.8.0)
railties (>= 3.2.5, < 5)
temple (0.6.7) temple (0.6.7)
term-ansicolor (1.3.0) term-ansicolor (1.3.0)
tins (~> 1.0) tins (~> 1.0)
...@@ -331,22 +348,22 @@ GEM ...@@ -331,22 +348,22 @@ GEM
eventmachine (>= 1.0.0) eventmachine (>= 1.0.0)
rack (>= 1.0.0) rack (>= 1.0.0)
thor (0.19.1) thor (0.19.1)
thread_safe (0.3.1) thread_safe (0.3.3)
atomic (>= 1.1.7, < 2)
tilt (1.4.1) tilt (1.4.1)
timers (1.1.0) timers (1.1.0)
tins (1.0.1) tins (1.1.0)
treetop (1.4.15) treetop (1.4.15)
polyglot polyglot
polyglot (>= 0.3.1) polyglot (>= 0.3.1)
turnip (1.2.1) turnip (1.2.1)
gherkin (>= 2.5) gherkin (>= 2.5)
rspec (>= 2.0, < 4.0) rspec (>= 2.0, < 4.0)
tzinfo (0.3.39) tzinfo (1.1.0)
thread_safe (~> 0.1)
uglifier (2.5.0) uglifier (2.5.0)
execjs (>= 0.3.0) execjs (>= 0.3.0)
json (>= 1.8.0) json (>= 1.8.0)
unf (0.1.3) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.6) unf_ext (0.0.6)
uuidtools (2.1.4) uuidtools (2.1.4)
...@@ -364,6 +381,7 @@ PLATFORMS ...@@ -364,6 +381,7 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
action-gmailer! action-gmailer!
ancestry ancestry
annotate (>= 2.6.0)
aws-sdk aws-sdk
better_errors better_errors
binding_of_caller binding_of_caller
...@@ -378,12 +396,14 @@ DEPENDENCIES ...@@ -378,12 +396,14 @@ DEPENDENCIES
coveralls coveralls
database_rewinder database_rewinder
devise devise
devise-better_routes
draper (~> 1.3) draper (~> 1.3)
factory_girl_rails factory_girl_rails
faraday faraday
github-markdown github-markdown
guard-rspec guard-rspec
guard-rubocop guard-rubocop
guard-teaspoon
i18n_generators i18n_generators
jbuilder jbuilder
jquery-rails jquery-rails
...@@ -397,6 +417,7 @@ DEPENDENCIES ...@@ -397,6 +417,7 @@ DEPENDENCIES
poltergeist poltergeist
premailer premailer
pry-rails pry-rails
rack-mini-profiler
rails (~> 4) rails (~> 4)
rspec-rails rspec-rails
rubocop rubocop
...@@ -404,6 +425,7 @@ DEPENDENCIES ...@@ -404,6 +425,7 @@ DEPENDENCIES
sdoc sdoc
settingslogic settingslogic
slim slim
teaspoon
therubyracer therubyracer
thin thin
turnip turnip
......
...@@ -16,3 +16,7 @@ guard :rspec do ...@@ -16,3 +16,7 @@ guard :rspec do
watch(%r{^spec/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' } watch(%r{^spec/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
end end
guard :teaspoon do
watch(%r{^app/assets/javascripts/(.+).js}) { |m| "spec/javascripts/#{m[1]}_spec.js.coffee" }
watch(%r{^spec/javascripts/(.*)})
end
# 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/
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
// require turbolinks // require turbolinks
//= require ./lib/jquery.ui.widget //= require ./lib/jquery.ui.widget
//= require_tree ./lib //= require_tree ./lib
//= require_tree ./modules
//= require_tree . //= require_tree .
_.mixin(_.string.exports()); _.mixin(_.string.exports());
......
# 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/
<!DOCTYPE HTML>
<!--
/*
* jQuery File Upload Plugin Demo 9.0.1
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/MIT
*/
-->
<html lang="en">
<head>
<!-- Force latest IE rendering engine or ChromeFrame if installed -->
<!--[if IE]>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<![endif]-->
<meta charset="utf-8">
<title>jQuery File Upload Demo</title>
<meta name="description" content="File Upload widget with multiple file selection, drag&amp;drop support, progress bars, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap styles -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
<!-- Generic page styles -->
<link rel="stylesheet" href="css/style.css">
<!-- blueimp Gallery styles -->
<link rel="stylesheet" href="http://blueimp.github.io/Gallery/css/blueimp-gallery.min.css">
<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
<link rel="stylesheet" href="css/jquery.fileupload.css">
<link rel="stylesheet" href="css/jquery.fileupload-ui.css">
<!-- CSS adjustments for browsers with JavaScript disabled -->
<noscript><link rel="stylesheet" href="css/jquery.fileupload-noscript.css"></noscript>
<noscript><link rel="stylesheet" href="css/jquery.fileupload-ui-noscript.css"></noscript>
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-fixed-top .navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="https://github.com/blueimp/jQuery-File-Upload">jQuery File Upload</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="https://github.com/blueimp/jQuery-File-Upload/tags">Download</a></li>
<li><a href="https://github.com/blueimp/jQuery-File-Upload">Source Code</a></li>
<li><a href="https://github.com/blueimp/jQuery-File-Upload/wiki">Documentation</a></li>
<li><a href="https://blueimp.net">&copy; Sebastian Tschan</a></li>
</ul>
</div>
</div>
</div>
<div class="container">
<h1>jQuery File Upload Demo</h1>
<h2 class="lead">Basic Plus UI version</h2>
<ul class="nav nav-tabs">
<li><a href="basic.html">Basic</a></li>
<li><a href="basic-plus.html">Basic Plus</a></li>
<li class="active"><a href="index.html">Basic Plus UI</a></li>
<li><a href="angularjs.html">AngularJS</a></li>
<li><a href="jquery-ui.html">jQuery UI</a></li>
</ul>
<br>
<blockquote>
<p>File Upload widget with multiple file selection, drag&amp;drop support, progress bars, validation and preview images, audio and video for jQuery.<br>
Supports cross-domain, chunked and resumable file uploads and client-side image resizing.<br>
Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.</p>
</blockquote>
<br>
<!-- The file upload form used as target for the file upload widget -->
<form id="fileupload" action="//jquery-file-upload.appspot.com/" method="POST" enctype="multipart/form-data">
<!-- Redirect browsers with JavaScript disabled to the origin page -->
<noscript><input type="hidden" name="redirect" value="http://blueimp.github.io/jQuery-File-Upload/"></noscript>
<!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
<div class="row fileupload-buttonbar">
<div class="col-lg-7">
<!-- The fileinput-button span is used to style the file input field as button -->
<span class="btn btn-success fileinput-button">
<i class="glyphicon glyphicon-plus"></i>
<span>Add files...</span>
<input type="file" name="files[]" multiple>
</span>
<button type="submit" class="btn btn-primary start">
<i class="glyphicon glyphicon-upload"></i>
<span>Start upload</span>
</button>
<button type="reset" class="btn btn-warning cancel">
<i class="glyphicon glyphicon-ban-circle"></i>
<span>Cancel upload</span>
</button>
<button type="button" class="btn btn-danger delete">
<i class="glyphicon glyphicon-trash"></i>
<span>Delete</span>
</button>
<input type="checkbox" class="toggle">
<!-- The global file processing state -->
<span class="fileupload-process"></span>
</div>
<!-- The global progress state -->
<div class="col-lg-5 fileupload-progress fade">
<!-- The global progress bar -->
<div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100">
<div class="progress-bar progress-bar-success" style="width:0%;"></div>
</div>
<!-- The extended global progress state -->
<div class="progress-extended">&nbsp;</div>
</div>
</div>
<!-- The table listing the files available for upload/download -->
<table role="presentation" class="table table-striped"><tbody class="files"></tbody></table>
</form>
<br>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Demo Notes</h3>
</div>
<div class="panel-body">
<ul>
<li>The maximum file size for uploads in this demo is <strong>5 MB</strong> (default file size is unlimited).</li>
<li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li>
<li>Uploaded files will be deleted automatically after <strong>5 minutes</strong> (demo setting).</li>
<li>You can <strong>drag &amp; drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li>
<li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li>
<li>Built with Twitter's <a href="http://twitter.github.com/bootstrap/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li>
</ul>
</div>
</div>
</div>
<!-- The blueimp Gallery widget -->
<div id="blueimp-gallery" class="blueimp-gallery blueimp-gallery-controls" data-filter=":even">
<div class="slides"></div>
<h3 class="title"></h3>
<a class="prev"></a>
<a class="next"></a>
<a class="close">×</a>
<a class="play-pause"></a>
<ol class="indicator"></ol>
</div>
<!-- The template to display files available for upload -->
<script id="template-upload" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
<tr class="template-upload fade">
<td>
<span class="preview"></span>
</td>
<td>
<p class="name">{%=file.name%}</p>
<strong class="error text-danger"></strong>
</td>
<td>
<p class="size">Processing...</p>
<div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="progress-bar progress-bar-success" style="width:0%;"></div></div>
</td>
<td>
{% if (!i && !o.options.autoUpload) { %}
<button class="btn btn-primary start" disabled>
<i class="glyphicon glyphicon-upload"></i>
<span>Start</span>
</button>
{% } %}
{% if (!i) { %}
<button class="btn btn-warning cancel">
<i class="glyphicon glyphicon-ban-circle"></i>
<span>Cancel</span>
</button>
{% } %}
</td>
</tr>
{% } %}
</script>
<!-- The template to display files available for download -->
<script id="template-download" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
<tr class="template-download fade">
<td>
<span class="preview">
{% if (file.thumbnailUrl) { %}
<a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img src="{%=file.thumbnailUrl%}"></a>
{% } %}
</span>
</td>
<td>
<p class="name">
{% if (file.url) { %}
<a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?'data-gallery':''%}>{%=file.name%}</a>
{% } else { %}
<span>{%=file.name%}</span>
{% } %}
</p>
{% if (file.error) { %}
<div><span class="label label-danger">Error</span> {%=file.error%}</div>
{% } %}
</td>
<td>
<span class="size">{%=o.formatFileSize(file.size)%}</span>
</td>
<td>
{% if (file.deleteUrl) { %}
<button class="btn btn-danger delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}>
<i class="glyphicon glyphicon-trash"></i>
<span>Delete</span>
</button>
<input type="checkbox" name="delete" value="1" class="toggle">
{% } else { %}
<button class="btn btn-warning cancel">
<i class="glyphicon glyphicon-ban-circle"></i>
<span>Cancel</span>
</button>
{% } %}
</td>
</tr>
{% } %}
</script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<script src="js/vendor/jquery.ui.widget.js"></script>
<!-- The Templates plugin is included to render the upload/download listings -->
<script src="http://blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script>
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
<script src="http://blueimp.github.io/JavaScript-Load-Image/js/load-image.min.js"></script>
<!-- The Canvas to Blob plugin is included for image resizing functionality -->
<script src="http://blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
<!-- blueimp Gallery script -->
<script src="http://blueimp.github.io/Gallery/js/jquery.blueimp-gallery.min.js"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
<script src="js/jquery.iframe-transport.js"></script>
<!-- The basic File Upload plugin -->
<script src="js/jquery.fileupload.js"></script>
<!-- The File Upload processing plugin -->
<script src="js/jquery.fileupload-process.js"></script>
<!-- The File Upload image preview & resize plugin -->
<script src="js/jquery.fileupload-image.js"></script>
<!-- The File Upload audio preview plugin -->
<script src="js/jquery.fileupload-audio.js"></script>
<!-- The File Upload video preview plugin -->
<script src="js/jquery.fileupload-video.js"></script>
<!-- The File Upload validation plugin -->
<script src="js/jquery.fileupload-validate.js"></script>
<!-- The File Upload user interface plugin -->
<script src="js/jquery.fileupload-ui.js"></script>
<!-- The main application script -->
<script src="js/main.js"></script>
<!-- The XDomainRequest Transport is included for cross-domain file deletion for IE 8 and IE 9 -->
<!--[if (gte IE 8)&(lt IE 10)]>
<script src="js/cors/jquery.xdr-transport.js"></script>
<![endif]-->
</body>
</html>
/*
Version: 3.4.5 Timestamp: Mon Nov 4 08:22:42 PST 2013
*/
.select2-container {
margin: 0;
position: relative;
display: inline-block;
/* inline-block for ie7 */
zoom: 1;
*display: inline;
vertical-align: middle;
}
.select2-container,
.select2-drop,
.select2-search,
.select2-search input {
/*
Force border-box so that % widths fit the parent
container without overlap because of margin/padding.
More Info : http://www.quirksmode.org/css/box.html
*/
-webkit-box-sizing: border-box; /* webkit */
-moz-box-sizing: border-box; /* firefox */
box-sizing: border-box; /* css3 */
}
.select2-container .select2-choice {
display: block;
height: 26px;
padding: 0 0 0 8px;
overflow: hidden;
position: relative;
border: 1px solid #aaa;
white-space: nowrap;
line-height: 26px;
color: #444;
text-decoration: none;
border-radius: 4px;
background-clip: padding-box;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background-color: #fff;
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.5, #fff));
background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 50%);
background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 50%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff', endColorstr = '#eeeeee', GradientType = 0);
background-image: linear-gradient(top, #fff 0%, #eee 50%);
}
.select2-container.select2-drop-above .select2-choice {
border-bottom-color: #aaa;
border-radius: 0 0 4px 4px;
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.9, #fff));
background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 90%);
background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 90%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
background-image: linear-gradient(top, #eee 0%, #fff 90%);
}
.select2-container.select2-allowclear .select2-choice .select2-chosen {
margin-right: 42px;
}
.select2-container .select2-choice > .select2-chosen {
margin-right: 26px;
display: block;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.select2-container .select2-choice abbr {
display: none;
width: 12px;
height: 12px;
position: absolute;
right: 24px;
top: 8px;
font-size: 1px;
text-decoration: none;
border: 0;
background: url('select2.png') right top no-repeat;
cursor: pointer;
outline: 0;
}
.select2-container.select2-allowclear .select2-choice abbr {
display: inline-block;
}
.select2-container .select2-choice abbr:hover {
background-position: right -11px;
cursor: pointer;
}
.select2-drop-mask {
border: 0;
margin: 0;
padding: 0;
position: fixed;
left: 0;
top: 0;
min-height: 100%;
min-width: 100%;
height: auto;
width: auto;
opacity: 0;
z-index: 9998;
/* styles required for IE to work */
background-color: #fff;
filter: alpha(opacity=0);
}
.select2-drop {
width: 100%;
margin-top: -1px;
position: absolute;
z-index: 9999;
top: 100%;
background: #fff;
color: #000;
border: 1px solid #aaa;
border-top: 0;
border-radius: 0 0 4px 4px;
-webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
}
.select2-drop-auto-width {
border-top: 1px solid #aaa;
width: auto;
}
.select2-drop-auto-width .select2-search {
padding-top: 4px;
}
.select2-drop.select2-drop-above {
margin-top: 1px;
border-top: 1px solid #aaa;
border-bottom: 0;
border-radius: 4px 4px 0 0;
-webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
}
.select2-drop-active {
border: 1px solid #5897fb;
border-top: none;
}
.select2-drop.select2-drop-above.select2-drop-active {
border-top: 1px solid #5897fb;
}
.select2-container .select2-choice .select2-arrow {
display: inline-block;
width: 18px;
height: 100%;
position: absolute;
right: 0;
top: 0;
border-left: 1px solid #aaa;
border-radius: 0 4px 4px 0;
background-clip: padding-box;
background: #ccc;
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee));
background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%);
background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#cccccc', GradientType = 0);
background-image: linear-gradient(top, #ccc 0%, #eee 60%);
}
.select2-container .select2-choice .select2-arrow b {
display: block;
width: 100%;
height: 100%;
background: url('select2.png') no-repeat 0 1px;
}
.select2-search {
display: inline-block;
width: 100%;
min-height: 26px;
margin: 0;
padding-left: 4px;
padding-right: 4px;
position: relative;
z-index: 10000;
white-space: nowrap;
}
.select2-search input {
width: 100%;
height: auto !important;
min-height: 26px;
padding: 4px 20px 4px 5px;
margin: 0;
outline: 0;
font-family: sans-serif;
font-size: 1em;
border: 1px solid #aaa;
border-radius: 0;
-webkit-box-shadow: none;
box-shadow: none;
background: #fff url('select2.png') no-repeat 100% -22px;
background: url('select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
background: url('select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
background: url('select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
background: url('select2.png') no-repeat 100% -22px, linear-gradient(top, #fff 85%, #eee 99%);
}
.select2-drop.select2-drop-above .select2-search input {
margin-top: 4px;
}
.select2-search input.select2-active {
background: #fff url('select2-spinner.gif') no-repeat 100%;
background: url('select2-spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
background: url('select2-spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
background: url('select2-spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
background: url('select2-spinner.gif') no-repeat 100%, linear-gradient(top, #fff 85%, #eee 99%);
}
.select2-container-active .select2-choice,
.select2-container-active .select2-choices {
border: 1px solid #5897fb;
outline: none;
-webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
box-shadow: 0 0 5px rgba(0, 0, 0, .3);
}
.select2-dropdown-open .select2-choice {
border-bottom-color: transparent;
-webkit-box-shadow: 0 1px 0 #fff inset;
box-shadow: 0 1px 0 #fff inset;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
background-color: #eee;
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(0.5, #eee));
background-image: -webkit-linear-gradient(center bottom, #fff 0%, #eee 50%);
background-image: -moz-linear-gradient(center bottom, #fff 0%, #eee 50%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);
background-image: linear-gradient(top, #fff 0%, #eee 50%);
}
.select2-dropdown-open.select2-drop-above .select2-choice,
.select2-dropdown-open.select2-drop-above .select2-choices {
border: 1px solid #5897fb;
border-top-color: transparent;
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(0.5, #eee));
background-image: -webkit-linear-gradient(center top, #fff 0%, #eee 50%);
background-image: -moz-linear-gradient(center top, #fff 0%, #eee 50%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);
background-image: linear-gradient(bottom, #fff 0%, #eee 50%);
}
.select2-dropdown-open .select2-choice .select2-arrow {
background: transparent;
border-left: none;
filter: none;
}
.select2-dropdown-open .select2-choice .select2-arrow b {
background-position: -18px 1px;
}
/* results */
.select2-results {
max-height: 200px;
padding: 0 0 0 4px;
margin: 4px 4px 4px 0;
position: relative;
overflow-x: hidden;
overflow-y: auto;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.select2-results ul.select2-result-sub {
margin: 0;
padding-left: 0;
}
.select2-results ul.select2-result-sub > li .select2-result-label { padding-left: 20px }
.select2-results ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 40px }
.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 60px }
.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 80px }
.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 100px }
.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 110px }
.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 120px }
.select2-results li {
list-style: none;
display: list-item;
background-image: none;
}
.select2-results li.select2-result-with-children > .select2-result-label {
font-weight: bold;
}
.select2-results .select2-result-label {
padding: 3px 7px 4px;
margin: 0;
cursor: pointer;
min-height: 1em;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.select2-results .select2-highlighted {
background: #3875d7;
color: #fff;
}
.select2-results li em {
background: #feffde;
font-style: normal;
}
.select2-results .select2-highlighted em {
background: transparent;
}
.select2-results .select2-highlighted ul {
background: #fff;
color: #000;
}
.select2-results .select2-no-results,
.select2-results .select2-searching,
.select2-results .select2-selection-limit {
background: #f4f4f4;
display: list-item;
}
/*
disabled look for disabled choices in the results dropdown
*/
.select2-results .select2-disabled.select2-highlighted {
color: #666;
background: #f4f4f4;
display: list-item;
cursor: default;
}
.select2-results .select2-disabled {
background: #f4f4f4;
display: list-item;
cursor: default;
}
.select2-results .select2-selected {
display: none;
}
.select2-more-results.select2-active {
background: #f4f4f4 url('select2-spinner.gif') no-repeat 100%;
}
.select2-more-results {
background: #f4f4f4;
display: list-item;
}
/* disabled styles */
.select2-container.select2-container-disabled .select2-choice {
background-color: #f4f4f4;
background-image: none;
border: 1px solid #ddd;
cursor: default;
}
.select2-container.select2-container-disabled .select2-choice .select2-arrow {
background-color: #f4f4f4;
background-image: none;
border-left: 0;
}
.select2-container.select2-container-disabled .select2-choice abbr {
display: none;
}
/* multiselect */
.select2-container-multi .select2-choices {
height: auto !important;
height: 1%;
margin: 0;
padding: 0;
position: relative;
border: 1px solid #aaa;
cursor: text;
overflow: hidden;
background-color: #fff;
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eee), color-stop(15%, #fff));
background-image: -webkit-linear-gradient(top, #eee 1%, #fff 15%);
background-image: -moz-linear-gradient(top, #eee 1%, #fff 15%);
background-image: linear-gradient(top, #eee 1%, #fff 15%);
}
.select2-locked {
padding: 3px 5px 3px 5px !important;
}
.select2-container-multi .select2-choices {
min-height: 26px;
}
.select2-container-multi.select2-container-active .select2-choices {
border: 1px solid #5897fb;
outline: none;
-webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
box-shadow: 0 0 5px rgba(0, 0, 0, .3);
}
.select2-container-multi .select2-choices li {
float: left;
list-style: none;
}
.select2-container-multi .select2-choices .select2-search-field {
margin: 0;
padding: 0;
white-space: nowrap;
}
.select2-container-multi .select2-choices .select2-search-field input {
padding: 5px;
margin: 1px 0;
font-family: sans-serif;
font-size: 100%;
color: #666;
outline: 0;
border: 0;
-webkit-box-shadow: none;
box-shadow: none;
background: transparent !important;
}
.select2-container-multi .select2-choices .select2-search-field input.select2-active {
background: #fff url('select2-spinner.gif') no-repeat 100% !important;
}
.select2-default {
color: #999 !important;
}
.select2-container-multi .select2-choices .select2-search-choice {
padding: 3px 5px 3px 18px;
margin: 3px 0 3px 5px;
position: relative;
line-height: 13px;
color: #333;
cursor: default;
border: 1px solid #aaaaaa;
border-radius: 3px;
-webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
background-clip: padding-box;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background-color: #e4e4e4;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#f4f4f4', GradientType=0);
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eee));
background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
}
.select2-container-multi .select2-choices .select2-search-choice .select2-chosen {
cursor: default;
}
.select2-container-multi .select2-choices .select2-search-choice-focus {
background: #d4d4d4;
}
.select2-search-choice-close {
display: block;
width: 12px;
height: 13px;
position: absolute;
right: 3px;
top: 4px;
font-size: 1px;
outline: none;
background: url('select2.png') right top no-repeat;
}
.select2-container-multi .select2-search-choice-close {
left: 3px;
}
.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover {
background-position: right -11px;
}
.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close {
background-position: right -11px;
}
/* disabled styles */
.select2-container-multi.select2-container-disabled .select2-choices {
background-color: #f4f4f4;
background-image: none;
border: 1px solid #ddd;
cursor: default;
}
.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice {
padding: 3px 5px 3px 5px;
border: 1px solid #ddd;
background-image: none;
background-color: #f4f4f4;
}
.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none;
background: none;
}
/* end multiselect */
.select2-result-selectable .select2-match,
.select2-result-unselectable .select2-match {
text-decoration: underline;
}
.select2-offscreen, .select2-offscreen:focus {
clip: rect(0 0 0 0) !important;
width: 1px !important;
height: 1px !important;
border: 0 !important;
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
position: absolute !important;
outline: 0 !important;
left: 0px !important;
top: 0px !important;
}
.select2-display-none {
display: none;
}
.select2-measure-scrollbar {
position: absolute;
top: -10000px;
left: -10000px;
width: 100px;
height: 100px;
overflow: scroll;
}
/* Retina-ize icons */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi) {
.select2-search input, .select2-search-choice-close, .select2-container .select2-choice abbr, .select2-container .select2-choice .select2-arrow b {
background-image: url('select2x2.png') !important;
background-repeat: no-repeat !important;
background-size: 60px 40px !important;
}
.select2-search input {
background-position: 100% -21px !important;
}
}
# TODO:
# mod-mdEditorがページ内に複数あった場合の処理
@_mod_md_editor = {}
class @_mod_md_editor.TextareaText
constructor: (@text, @sel_start, @sel_end) ->
total_line_num: ->
99
current_line_num: ->
80
current_line_head_pos: ->
70
current_pos_in_line: ->
4
$.fn.extend
mod_mdEditor: (options) ->
settings =
# preview api url
end_point: ''
settings = $.extend settings, options
return @each () ->
$root = $(@)
$textarea = $root.find('.mod-mdEditor-textarea')
# textareのサイズ調整
$textarea.autosize();
# textareaのtabキー制御,indent維持
$textarea.on 'keydown', (e) ->
$this = $(@)
keyCode = e.keyCode || e.which
# tab key
if keyCode is 9
e.preventDefault()
start = $this.get(0).selectionStart
end = $this.get(0).selectionEnd
# set textarea value to: text before caret + tab + text after caret
$this.val($this.val().substring(0, start) +
'\t' +
$this.val().substring(end))
# put caret at right position again
$this.get(0).selectionStart =
$this.get(0).selectionEnd = start + 1
# enter key
else if keyCode is 13
e.preventDefault()
val = $this.val()
start = $this.get(0).selectionStart
bl = val.lastIndexOf("\n", start-1)
line = val.substring(bl, start)
lm = line.match(/^\s+/)
ns = if lm? then lm[0].length - 1 else 0
nv = val.substring(0, start) + "\n"
_(ns).times ->
nv += "\t"
$this.val(nv + val.substring(start))
$this.get(0).selectionStart =
$this.get(0).selectionEnd = start + ns + 1
# タグを選択可能に
$root.find('.mod-mdEditor-tags').select2 {
tags: window.RV.AllTags
}
# Previewを生成
generatePreview = ->
$.post(settings.end_point, {
'text': $textarea.val()
'authenticity_token': $("meta[name='csrf-token']").attr('content')
})
.done (data) ->
$root.find('.mod-mdEditor-preview').html(data)
# TODO
prettyPrint()
$textarea.on('keyup mouseup change', generatePreview)
generatePreview()
# textの行数をcount
count_line_number = (text) ->
matches = text.match(/\n/g)
if matches? then matches.length + 1 else 1
replace_regexp_meta = (str) ->
str.replace(/([\.\^\$\[\]\*\+\?\|\(\)])/g, "\\$1")
# 行の先頭に文字を挿入
md_head_insert_string = (insert_str) ->
textarea_text = $textarea.val()
sel_start_pos = $textarea.get(0).selectionStart
# sel_end_pos = $textarea.get(0).selectionEnd
# # textの全行数
# line_num = count_line_number(textarea_text)
# # 現在行の行数
# current_line_num = count_line_number(textarea_text.substr(0, sel_start_pos))
# 現在行の最初の文字の位置
current_line_head_pos = textarea_text.lastIndexOf("\n", sel_start_pos - 1) + 1
# 現在行のカーソル位置
current_pos_in_line = sel_start_pos - current_line_head_pos
# すでに挿入済みの場合は取り除く
insert_str_re = new RegExp('^' + replace_regexp_meta(insert_str), "g") # TODO ?
if textarea_text.substring(current_line_head_pos).match(insert_str_re)
$textarea.val([
textarea_text.substring(0, current_line_head_pos),
textarea_text.substring(current_line_head_pos).replace(insert_str_re, '')
].join(''))
else
$textarea.val([
textarea_text.substring(0, current_line_head_pos),
insert_str,
textarea_text.substring(current_line_head_pos)
].join(''))
# 選択文字を囲う
md_wrap_string = (wrap_str) ->
textarea_text = $textarea.val()
sel_start_pos = $textarea.get(0).selectionStart
sel_end_pos = $textarea.get(0).selectionEnd
# 文字が選択されていなければplaceholderを挿入
if sel_start_pos == sel_end_pos
placeholder_str = '<ここに文字>'
$textarea.val([
textarea_text.substring(0, sel_start_pos),
placeholder_str,
textarea_text.substring(sel_end_pos)
].join(''))
$textarea.get(0).selectionEnd = sel_end_pos + 2 + 2 * wrap_str.length + placeholder_str.length
# execute self.
md_wrap_string(wrap_str)
return
# すでに挿入済みの場合は取り除く
wrap_str_re = new RegExp('^ ' + replace_regexp_meta(wrap_str))
wrap_str_re_end = new RegExp(replace_regexp_meta(wrap_str) + ' $')
if textarea_text.substring(sel_start_pos, sel_end_pos).match(wrap_str_re)
$textarea.val([
textarea_text.substring(0, sel_start_pos),
textarea_text.substring(sel_start_pos, sel_end_pos).
replace(wrap_str_re, '').
replace(wrap_str_re_end, ''),
textarea_text.substring(sel_end_pos)
].join(''))
else
$textarea.val([
textarea_text.substring(0, sel_start_pos),
' ',
wrap_str,
textarea_text.substring(sel_start_pos, sel_end_pos),
wrap_str,
' ',
textarea_text.substring(sel_end_pos)
].join(''))
# カーソルの終了位置を移動
$textarea.get(0).selectionEnd = sel_end_pos + 2 + 2 * wrap_str.length
$textarea.get(0).selectionStart = sel_start_pos
# WYSIWYG
$root.find('.mod-mdEditor-btn-h1').on 'click', (e) ->
e.preventDefault()
md_head_insert_string('# ')
generatePreview()
$root.find('.mod-mdEditor-btn-h2').on 'click', (e) ->
e.preventDefault()
md_head_insert_string('## ')
generatePreview()
$root.find('.mod-mdEditor-btn-h3').on 'click', (e) ->
e.preventDefault()
md_head_insert_string('### ')
generatePreview()
$root.find('.mod-mdEditor-btn-ol').on 'click', (e) ->
e.preventDefault()
md_head_insert_string('1. ')
generatePreview()
$root.find('.mod-mdEditor-btn-ul').on 'click', (e) ->
e.preventDefault()
md_head_insert_string('- ')
generatePreview()
$root.find('.mod-mdEditor-btn-bold').on 'click', (e) ->
e.preventDefault()
md_wrap_string('**')
generatePreview()
$root.find('.mod-mdEditor-btn-italic').on 'click', (e) ->
e.preventDefault()
md_wrap_string('_')
generatePreview()
$root.find('.mod-mdEditor-btn-strikethrough').on 'click', (e) ->
e.preventDefault()
md_wrap_string('~~')
generatePreview()
# 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/
# 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/
# 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/
# 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/
// Place all the styles related to the apis controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
* *
*= require normalize *= require normalize
*= require_tree ./lib *= require_tree ./lib
*= require_tree ./modules
*= require_tree . *= require_tree .
*= require_self *= require_self
*/ */
......
// Place all the styles related to the flow controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
/* Sample */ /* Sample */
/*
.dropdown-menu { .dropdown-menu {
border: 1px solid #ddd; border: 1px solid #ddd;
background-color: white; background-color: white;
...@@ -18,6 +20,7 @@ ...@@ -18,6 +20,7 @@
.dropdown-menu .active { .dropdown-menu .active {
background-color: rgb(110, 183, 219); background-color: rgb(110, 183, 219);
} }
*/
/* SHOULD not modify */ /* SHOULD not modify */
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
// } // }
// } // }
.mod-mdEditor-body { .mod-mdEditor-textarea {
width: 100%; width: 100%;
min-height: 400px; min-height: 400px;
font-size: 9pt; font-size: 9pt;
......
.panel-body.panel-body-nopadding {
padding: 0;
}
.panel-body textarea {
border: none;
border-top: 1px dashed #999;
}
// Place all the styles related to the posts controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
// Place all the styles related to the search controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
// Place all the styles related to the stock controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
// Place all the styles related to the tags controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
...@@ -2,6 +2,6 @@ class FlowController < ApplicationController ...@@ -2,6 +2,6 @@ class FlowController < ApplicationController
before_action :require_login before_action :require_login
def show def show
@posts = Post.where(is_draft: false).order(updated_at: :desc).limit(20).decorate @posts = Post.includes(:tags, :author).where(is_draft: false).order(updated_at: :desc).limit(20).decorate
end end
end end
class UsersController < ApplicationController class MeController < ApplicationController
before_action :set_user, only: [:edit, :update] before_action :set_user, only: [:edit, :update]
def edit def edit
...@@ -6,12 +6,12 @@ class UsersController < ApplicationController ...@@ -6,12 +6,12 @@ class UsersController < ApplicationController
def update def update
respond_to do |format| respond_to do |format|
if @user.update(user_params) if @me.update(user_params)
format.html { redirect_to edit_user_path, flash: { notice: 'Post was successfully updated.' } } format.html { redirect_to edit_me_path, flash: { notice: 'Post was successfully updated.' } }
format.json { head :no_content } format.json { head :no_content }
else else
format.html { render action: 'edit' } format.html { render action: 'edit' }
format.json { render json: @user.errors, status: :unprocessable_entity } format.json { render json: @me.errors, status: :unprocessable_entity }
end end
end end
end end
...@@ -20,7 +20,7 @@ class UsersController < ApplicationController ...@@ -20,7 +20,7 @@ class UsersController < ApplicationController
# Use callbacks to share common setup or constraints between actions. # Use callbacks to share common setup or constraints between actions.
def set_user def set_user
@user = current_user @me = current_user
end end
def user_params def user_params
......
...@@ -33,8 +33,7 @@ class PostsController < ApplicationController ...@@ -33,8 +33,7 @@ class PostsController < ApplicationController
# GET /posts/new # GET /posts/new
def new def new
@post = Post.new @post = Post.new(title: '新しい投稿')
@post.title = '新しい投稿'
end end
def fork def fork
......
...@@ -17,7 +17,7 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController ...@@ -17,7 +17,7 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
sign_in_and_redirect @user, event: :authentication sign_in_and_redirect @user, event: :authentication
else else
session['devise.google_data'] = request.env['omniauth.auth'] session['devise.google_data'] = request.env['omniauth.auth']
redirect_to new_user_registration_url redirect_to edit_me_path
end end
end end
end end
...@@ -27,4 +27,12 @@ class PostDecorator < Draper::Decorator ...@@ -27,4 +27,12 @@ class PostDecorator < Draper::Decorator
end end
end end
def display_specified_date
if model.specified_date
model.specified_date.strftime('%Y-%m-%d')
else
''
end
end
end end
...@@ -10,6 +10,8 @@ class TagDecorator < Draper::Decorator ...@@ -10,6 +10,8 @@ class TagDecorator < Draper::Decorator
# end # end
# end # end
decorates_association :posts
# tagページのURL # tagページのURL
# urlエンコードを施す # urlエンコードを施す
def show_path def show_path
...@@ -30,7 +32,7 @@ class TagDecorator < Draper::Decorator ...@@ -30,7 +32,7 @@ class TagDecorator < Draper::Decorator
_html += %Q{ _html += %Q{
<a href="#{ self.show_path }" data-name="#{model.name}"> <a href="#{ self.show_path }" data-name="#{model.name}">
#{model.name} <span class="badge">#{model.posts.count}</span> #{model.name} <span class="badge">#{model.posts.size}</span>
</a> </a>
} }
......
# == Schema Information
#
# Table name: comments
#
# id :integer not null, primary key
# author_id :integer
# post_id :integer
# body :text
# created_at :datetime
# updated_at :datetime
#
class Comment < ActiveRecord::Base class Comment < ActiveRecord::Base
belongs_to :author, class_name: 'User' belongs_to :author, class_name: 'User'
belongs_to :post belongs_to :post
......
# == Schema Information
#
# Table name: posts
#
# id :integer not null, primary key
# title :string(255)
# body :text
# author_id :integer
# created_at :datetime
# updated_at :datetime
# is_draft :boolean default(FALSE)
# specified_date :date
#
# specified_dateは特定の日付を指定したい場合に使用
class Post < ActiveRecord::Base class Post < ActiveRecord::Base
has_many :post_tags has_many :post_tags
has_many :tags, through: :post_tags has_many :tags, through: :post_tags
...@@ -46,6 +61,11 @@ class Post < ActiveRecord::Base ...@@ -46,6 +61,11 @@ class Post < ActiveRecord::Base
_where_list _where_list
end) end)
# 最新のPostを取得
scope :recent, -> (limit = 10) {
order(updated_at: :desc).limit(limit)
}
# generate forked post (not saved) # generate forked post (not saved)
def generate_fork(user) def generate_fork(user)
......
# == Schema Information
#
# Table name: post_tags
#
# id :integer not null, primary key
# post_id :integer not null
# tag_id :integer not null
# created_at :datetime
# updated_at :datetime
#
class PostTag < ActiveRecord::Base class PostTag < ActiveRecord::Base
belongs_to :post belongs_to :post
belongs_to :tag belongs_to :tag, counter_cache: 'posts_count'
end end
# == Schema Information
#
# Table name: tags
#
# id :integer not null, primary key
# name :string(255)
# created_at :datetime
# updated_at :datetime
# ancestry :string(255)
# body :text
#
class Tag < ActiveRecord::Base class Tag < ActiveRecord::Base
has_many :post_tags has_many :post_tags
has_many :posts, through: :post_tags has_many :posts, through: :post_tags
...@@ -17,6 +29,10 @@ class Tag < ActiveRecord::Base ...@@ -17,6 +29,10 @@ class Tag < ActiveRecord::Base
having('posts_count > 0') having('posts_count > 0')
} }
def recent_posts(limit = 30)
self.posts.recent(limit)
end
# 自分のタグに紐づくPostをすべて`other_tag`へ移動する # 自分のタグに紐づくPostをすべて`other_tag`へ移動する
def move_all_posts_to!(other_tag) def move_all_posts_to!(other_tag)
self.posts.each do |_post| self.posts.each do |_post|
......
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# name :string(255)
# image_url :string(255)
# created_at :datetime
# updated_at :datetime
# email :string(255) default(""), not null
# encrypted_password :string(255) default(""), not null
# reset_password_token :string(255)
# reset_password_sent_at :datetime
# remember_created_at :datetime
# sign_in_count :integer default(0), not null
# current_sign_in_at :datetime
# last_sign_in_at :datetime
# current_sign_in_ip :string(255)
# last_sign_in_ip :string(255)
# google_auth_token :string(255)
# google_refresh_token :string(255)
# google_token_expires_at :datetime
# nickname :string(255) default(""), not null
#
require 'faraday' require 'faraday'
class User < ActiveRecord::Base class User < ActiveRecord::Base
...@@ -37,20 +62,15 @@ class User < ActiveRecord::Base ...@@ -37,20 +62,15 @@ class User < ActiveRecord::Base
# Device # Device
def self.find_for_google_oauth2(access_token, signed_in_resource = nil) def self.find_for_google_oauth2(access_token, signed_in_resource = nil)
info = access_token.info
user = User.where(email: info['email']).first user = self.where(email: access_token.info['email']).first_or_create do |_user|
_user.name = access_token.info['name']
unless user _user.image_url = access_token.info['image']
new_nickname = (("a".."z").to_a + ("A".."Z").to_a + (0..9).to_a).shuffle[0..4].join _user.password = Devise.friendly_token[0, 20]
user = User.create(name: info['name'], _user.nickname = (("a".."z").to_a + ("A".."Z").to_a + (0..9).to_a).shuffle[0..4].join
image_url: info['image'],
email: info['email'],
password: Devise.friendly_token[0, 20],
nickname: new_nickname
)
end end
user.update_attributes( user.update(
google_auth_token: access_token.credentials['token'], google_auth_token: access_token.credentials['token'],
google_refresh_token: access_token.credentials['refresh_token'], google_refresh_token: access_token.credentials['refresh_token'],
google_token_expires_at: Time.at(access_token.credentials['expires_at']) google_token_expires_at: Time.at(access_token.credentials['expires_at'])
......
...@@ -8,6 +8,7 @@ html lang="ja" ...@@ -8,6 +8,7 @@ html lang="ja"
link href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap-theme.min.css" rel="stylesheet" / link href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap-theme.min.css" rel="stylesheet" /
link href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/1.6.4/fullcalendar.css" rel="stylesheet" / link href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/1.6.4/fullcalendar.css" rel="stylesheet" /
link href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/1.6.4/fullcalendar.print.css" rel="stylesheet" / link href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/1.6.4/fullcalendar.print.css" rel="stylesheet" /
link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet"
= stylesheet_link_tag "application", media: "all" = stylesheet_link_tag "application", media: "all"
= render_style = render_style
= csrf_meta_tags = csrf_meta_tags
......
#post-form #post-form
= form_for(@user) do |f| = form_for(@me, url: me_path) do |f|
- if @user.errors.any? - if @me.errors.any?
#error_explanation #error_explanation
h2 h2
= pluralize(@user.errors.count, "error") = pluralize(@me.errors.count, "error")
| prohibited this post from being saved: | prohibited this post from being saved:
ul ul
- @user.errors.full_messages.each do |msg| - @me.errors.full_messages.each do |msg|
li= msg li= msg
.row .row
......
...@@ -37,9 +37,9 @@ nav.navbar.navbar-default.navbar-fixed-top role="navigation" ...@@ -37,9 +37,9 @@ nav.navbar.navbar-default.navbar-fixed-top role="navigation"
| 下書き | 下書き
span.badge.pull-right = current_user.decorate.draft_count span.badge.pull-right = current_user.decorate.draft_count
li li
a href=edit_user_path(current_user) マイページ a href=edit_me_path マイページ
li.divider li.divider
li li
a href=sign_out_path data-method="delete" rel="nofollow" SignOut a href=me_session_path data-method="delete" rel="nofollow" SignOut
#post-form #post-form
= form_for(@post) do |f| = form_for(@post, role: 'form') do |f|
- if @post.errors.any? - if @post.errors.any?
#error_explanation #error_explanation
h2 h2
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
ul ul
- @post.errors.full_messages.each do |msg| - @post.errors.full_messages.each do |msg|
li= msg li= msg
.row .row
.col-xs-9 .col-xs-9
.field .field
...@@ -30,11 +31,35 @@ ...@@ -30,11 +31,35 @@
= f.date_select :specified_date = f.date_select :specified_date
br/ br/
.row .row
.col-xs-6.col-md-6 .col-xs-6
.field .panel.panel-default
= f.text_area :body, class: 'mod-mdEditor-body' .panel-heading
.col-xs-12.col-sm-6.col-md-6 .btn-toolbar role="toolbar"
.btn-group.btn-group-xs
button.btn.btn-default.mod-mdEditor-btn-h1 type="button" title="Header level 1" H1
button.btn.btn-default.mod-mdEditor-btn-h2 type="button" title="Header level 2" H2
button.btn.btn-default.mod-mdEditor-btn-h3 type="button" title="Header level 3" H3
.btn-group.btn-group-xs
button.btn.btn-default.mod-mdEditor-btn-bold type="button" title="Text bold"
i.fa.fa-bold
button.btn.btn-default.mod-mdEditor-btn-italic type="button" title="Text itelic"
i.fa.fa-italic
.btn-group.btn-group-xs
button.btn.btn-default.mod-mdEditor-btn-ol type="button" title="順序リスト"
i.fa.fa-list-ol
button.btn.btn-default.mod-mdEditor-btn-ul type="button" title="リスト"
i.fa.fa-list-ul
button.btn.btn-default.mod-mdEditor-btn-strikethrough type="button" title="打ち消し線"
i.fa.fa-strikethrough
/ button.btn.btn-default.mod-mdEditor-btn-link type="button"
/ i.fa.fa-link
.panel-body.panel-body-nopadding
= f.text_area :body, class: 'mod-mdEditor-textarea'
.col-xs-6
.box-text .box-text
.text-box.body.viewer.github.mod-mdEditor-preview .text-box.body.viewer.github.mod-mdEditor-preview
...@@ -42,13 +67,13 @@ input#fileupload data-url="/apis/file_receiver" multiple="" name="files[]" style ...@@ -42,13 +67,13 @@ input#fileupload data-url="/apis/file_receiver" multiple="" name="files[]" style
- content_for :footer_js do - content_for :footer_js do
javascript: javascript:
$.setConfirmUnload(); // $.setConfirmUnload();
$('#post-form').mod_mdEditor({end_point: '/apis/markdown_preview'}); $('#post-form').mod_mdEditor({end_point: '/apis/markdown_preview'});
$.mod_fileuploader({ $.mod_fileuploader({
$input: $('#fileupload'), $input: $('#fileupload'),
$textarea: $('.mod-mdEditor-body') $textarea: $('.mod-mdEditor-textarea')
}); });
// 下書き保存 // 下書き保存
......
...@@ -4,9 +4,10 @@ ...@@ -4,9 +4,10 @@
a.list-group-item.post-list.mod-hover-hidden data-post-id=post.id href=post_path(post) a.list-group-item.post-list.mod-hover-hidden data-post-id=post.id href=post_path(post)
.container-fluid .container-fluid
.row .row
.col-xs-10 .col-xs-9
h4.text-link #{post.title} h4.text-link #{post.title}
.col-xs-2 .col-xs-3
span.label.label-danger = post.display_specified_date if post.specified_date
small.pull-right small.pull-right
##{post.id} ##{post.id}
.row .row
...@@ -24,7 +25,7 @@ a.list-group-item.post-list.mod-hover-hidden data-post-id=post.id href=post_path ...@@ -24,7 +25,7 @@ a.list-group-item.post-list.mod-hover-hidden data-post-id=post.id href=post_path
span.mod-hover-hidden-item span.mod-hover-hidden-item
| 読了時間 | 読了時間
| &nbsp;#{post.read_time}&nbsp;&nbsp; | &nbsp;#{post.read_time}&nbsp;&nbsp;
span.glyphicon.glyphicon-edit span.glyphicon.glyphicon-comment
span.mod-hover-hidden-item span.mod-hover-hidden-item
| コメント | コメント
| &nbsp;#{post.comments.count}&nbsp;&nbsp; | &nbsp;#{post.comments.count}&nbsp;&nbsp;
......
...@@ -8,11 +8,13 @@ ...@@ -8,11 +8,13 @@
span.label.label-success span.label.label-success
a href=tag.decorate.show_path a href=tag.decorate.show_path
| ##{tag.name} | ##{tag.name}
| &nbsp;
span.label.label-info span.label.label-info
a href=(posts_path(q: "@#{@post.author.name}")) a href=(search_path(q: "@#{@post.author.name}"))
| @#{@post.author.name} | @#{@post.author.name}
| &nbsp;
span.label.label-danger span.label.label-danger
a href=(posts_path(q: "date:#{@post.display_date}")) = @post.display_date a href=(search_path(q: "date:#{@post.display_date}")) = @post.display_date
.btn-group.pull-right style=("margin: -7px -12px 0 0;") .btn-group.pull-right style=("margin: -7px -12px 0 0;")
a.btn.btn-primary href=edit_post_path(@post) a.btn.btn-primary href=edit_post_path(@post)
span.glyphicon.glyphicon-pencil span.glyphicon.glyphicon-pencil
......
/ locals: / locals:
/ post {Post} / post {Post}
a.list-group-item.post-list data-post-id=post.id href="#" = post.title a.list-group-item.post-list data-post-id=post.id href=post_path(post)
span.label.label-default.pull-right = post.display_specified_date if post.specified_date
= post.title
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
.col-xs-6.col-md-6 .col-xs-6.col-md-6
.field .field
/! <haml:loud> f.label :body </haml:loud><br /! <haml:loud> f.label :body </haml:loud><br
= f.text_area :body, class: 'mod-mdEditor-body' = f.text_area :body, class: 'mod-mdEditor-textarea'
/! /span /! /span
.col-xs-12.col-sm-6.col-md-6 .col-xs-12.col-sm-6.col-md-6
.box-text .box-text
......
...@@ -40,8 +40,10 @@ ...@@ -40,8 +40,10 @@
h2 h2
small small
|#{@tag.name}」のタグが付いた記事 |#{@tag.name}」のタグが付いた記事
- @tag.posts.each_with_index do |post, i| - @tag.recent_posts.each do |post|
a.list-group-item.post-list href=post_path(post) = post.title = render partial: 'posts/small_item', locals: { post: post.decorate }
a.list-group-item.post-list href=search_path(q: "##{@tag.name}") もっと見る
#modal-merge.modal.fade aria-hidden="true" aria-labelledby="myModalLabel" role="dialog" tabindex="-1" #modal-merge.modal.fade aria-hidden="true" aria-labelledby="myModalLabel" role="dialog" tabindex="-1"
.modal-dialog .modal-dialog
......
...@@ -33,4 +33,5 @@ module Rendezvous ...@@ -33,4 +33,5 @@ module Rendezvous
# account: 'FIXME' # account: 'FIXME'
} }
end end
end end
Teaspoon.setup do |config|
# This determines where the Teaspoon routes will be mounted. Changing this to "/jasmine" would allow you to browse to
# http://localhost:3000/jasmine to run your specs.
config.mount_at = "/teaspoon"
# This defaults to Rails.root if left nil. If you're testing an engine using a dummy application it can be useful to
# set this to your engines root.. E.g. `Teaspoon::Engine.root`
config.root = nil
# These paths are appended to the Rails assets paths (relative to config.root), and by default is an array that you
# can replace or add to.
config.asset_paths = ["spec/javascripts", "spec/javascripts/stylesheets"]
# Fixtures are rendered through a standard controller. This means you can use things like HAML or RABL/JBuilder, etc.
# to generate fixtures within this path.
config.fixture_path = "spec/javascripts/fixtures"
# You can modify the default suite configuration and create new suites here. Suites can be isolated from one another.
# When defining a suite you can provide a name and a block. If the name is left blank, :default is assumed. You can
# omit various directives and the defaults will be used.
#
# To run a specific suite
# - in the browser: http://localhost/teaspoon/[suite_name]
# - from the command line: rake teaspoon suite=[suite_name]
config.suite do |suite|
# You can specify a file matcher and all matching files will be loaded when the suite is run. It's important that
# these files are serve-able from sprockets.
#
# Note: Can also be set to nil.
suite.matcher = "{spec/javascripts,app/assets}/**/*_spec.{js,js.coffee,coffee}"
# Each suite can load a different helper, which can in turn require additional files. This file is loaded before
# your specs are loaded, and can be used as a manifest.
suite.helper = "spec_helper"
# These are the core Teaspoon javascripts. It's strongly encouraged to include only the base files here. You can
# require other support libraries in your spec helper, which allows you to change them without having to restart the
# server.
#
# Available frameworks: teaspoon-jasmine, teaspoon-mocha, teaspoon-qunit
#
# Note: To use the CoffeeScript source files use `"teaspoon/jasmine"` etc.
suite.javascripts = ["teaspoon-jasmine"]
# If you want to change how Teaspoon looks, or include your own stylesheets you can do that here. The default is the
# stylesheet for the HTML reporter.
suite.stylesheets = ["teaspoon"]
# When running coverage reports, you probably want to exclude libraries that you're not testing.
# Accepts an array of filenames or regular expressions. The default is to exclude assets from vendors or gems.
suite.no_coverage = [%r{/lib/ruby/gems/}, %r{/vendor/assets/}, %r{/support/}, %r{/(.+)_helper.}]
# suite.no_coverage << "jquery.min.js" # excludes jquery from coverage reports
end
# Example suite. Since we're just filtering to files already within the root spec/javascripts, these files will also
# be run in the default suite -- but can be focused into a more specific suite.
#config.suite :targeted do |suite|
# suite.matcher = "spec/javascripts/targeted/*_spec.{js,js.coffee,coffee}"
#end
end if defined?(Teaspoon) && Teaspoon.respond_to?(:setup) # let Teaspoon be undefined outside of development/test/asset groups
...@@ -21,15 +21,22 @@ Rendezvous::Application.routes.draw do ...@@ -21,15 +21,22 @@ Rendezvous::Application.routes.draw do
post 'tags/:name/move_to/:move_to_name' => 'tags#move_to', as: 'move_to_tag' post 'tags/:name/move_to/:move_to_name' => 'tags#move_to', as: 'move_to_tag'
resources :tags, :param => :name resources :tags, :param => :name
resource :user, :only => [:edit, :update] # resource :user, :only => [:edit, :update]
# devise_for :users , controllers: { omniauth_callbacks: 'users/omniauth_callbacks' } # devise_for :users , controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
# devise_for :users , only: [:sign_in, :sign_out, :session] # devise_for :users , only: [:sign_in, :sign_out, :session]
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }, skip: [:sessions]
devise_scope :user do devise_for :users,
path_names: { current_user: 'me' },
controllers: { omniauth_callbacks: 'users/omniauth_callbacks' },
skip: [:passwords]
# , controllers: { omniauth_callbacks: 'users/omniauth_callbacks' } # , skip: [:sessions]
# devise_scope :user do
# get 'sign_in', to: 'users/sessions#new', as: :new_user_session # get 'sign_in', to: 'users/sessions#new', as: :new_user_session
delete 'sign_out', to: 'devise/sessions#destroy', as: :sign_out # delete 'sign_out', to: 'devise/sessions#destroy', as: :sign_out
end # end
# get 'users/edit' => 'users#edit', as: 'edit_user' # get 'users/edit' => 'users#edit', as: 'edit_user'
# post 'users/update' => 'users#update', as: 'update_user' # post 'users/update' => 'users#update', as: 'update_user'
......
class AddPostsCountToTags < ActiveRecord::Migration
def change
add_column :tags, :posts_count, :integer, default: 0, null: false
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20140328045902) do ActiveRecord::Schema.define(version: 20140420120819) do
create_table "comments", force: true do |t| create_table "comments", force: true do |t|
t.integer "author_id" t.integer "author_id"
...@@ -52,6 +52,7 @@ ActiveRecord::Schema.define(version: 20140328045902) do ...@@ -52,6 +52,7 @@ ActiveRecord::Schema.define(version: 20140328045902) do
t.datetime "updated_at" t.datetime "updated_at"
t.string "ancestry" t.string "ancestry"
t.text "body" t.text "body"
t.integer "posts_count", default: 0, null: false
end end
add_index "tags", ["ancestry"], name: "index_tags_on_ancestry", using: :btree add_index "tags", ["ancestry"], name: "index_tags_on_ancestry", using: :btree
......
namespace :batch do
desc 'Tagに関連するPostのcounter_cacheの再生成'
task reset_counters: :environment do
Tag.all.each{|t| Tag.reset_counters(t.id, :posts) }
end
end
require 'spec_helper' require 'spec_helper'
describe UsersController do describe MeController do
before do before do
end end
...@@ -17,7 +17,7 @@ describe UsersController do ...@@ -17,7 +17,7 @@ describe UsersController do
login_user login_user
it "returns http success" do it "returns http success" do
patch :update, user: { nickname: 'bob' } patch :update, user: { nickname: 'bob' }
response.should redirect_to('/user/edit') response.should redirect_to('/me/edit')
end end
end end
......
# == Schema Information
#
# Table name: comments
#
# id :integer not null, primary key
# author_id :integer
# post_id :integer
# body :text
# created_at :datetime
# updated_at :datetime
#
# FactoryGirl.define do # FactoryGirl.define do
# factory :comment_1, class: Comment do # factory :comment_1, class: Comment do
# body 'ruby' # body 'ruby'
......
# == Schema Information
#
# Table name: posts
#
# id :integer not null, primary key
# title :string(255)
# body :text
# author_id :integer
# created_at :datetime
# updated_at :datetime
# is_draft :boolean default(FALSE)
# specified_date :date
#
# Read about factories at https://github.com/thoughtbot/factory_girl # Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do FactoryGirl.define do
......
# == Schema Information
#
# Table name: tags
#
# id :integer not null, primary key
# name :string(255)
# created_at :datetime
# updated_at :datetime
# ancestry :string(255)
# body :text
#
# Read about factories at https://github.com/thoughtbot/factory_girl # Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do FactoryGirl.define do
......
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# name :string(255)
# image_url :string(255)
# created_at :datetime
# updated_at :datetime
# email :string(255) default(""), not null
# encrypted_password :string(255) default(""), not null
# reset_password_token :string(255)
# reset_password_sent_at :datetime
# remember_created_at :datetime
# sign_in_count :integer default(0), not null
# current_sign_in_at :datetime
# last_sign_in_at :datetime
# current_sign_in_ip :string(255)
# last_sign_in_ip :string(255)
# google_auth_token :string(255)
# google_refresh_token :string(255)
# google_token_expires_at :datetime
# nickname :string(255) default(""), not null
#
FactoryGirl.define do FactoryGirl.define do
factory :alice, class: User do factory :alice, class: User do
name 'Alice' name 'Alice'
......
#= require modules/mod-md-editor
# describe "mod-md-editor", ->
# text = new _mod_md_editor.TextareaText("aaaaaaaa\nbbbbbb\n\ncccccc", 10, 18)
# it "_mod_md_editor.parse", ->
# expect(text.total_line_num()).toBe(4)
# expect(text.current_line_num()).toBe()
# expect(text.current_line_head_pos()).toBe(4)
# expect(text.current_pos_in_line()).toBe(4)
# Teaspoon includes some support files, but you can use anything from your own support path too.
# require support/jasmine-jquery-1.7.0
# require support/jasmine-jquery-2.0.0
# require support/sinon
# require support/your-support-file
#
# PhantomJS (Teaspoons default driver) doesn't have support for Function.prototype.bind, which has caused confusion.
# Use this polyfill to avoid the confusion.
#= require support/bind-poly
#
# Deferring execution
# If you're using CommonJS, RequireJS or some other asynchronous library you can defer execution. Call
# Teaspoon.execute() after everything has been loaded. Simple example of a timeout:
#
# Teaspoon.defer = true
# setTimeout(Teaspoon.execute, 1000)
#
# Matching files
# By default Teaspoon will look for files that match _spec.{js,js.coffee,.coffee}. Add a filename_spec.js file in your
# spec path and it'll be included in the default suite automatically. If you want to customize suites, check out the
# configuration in config/initializers/teaspoon.rb
#
# Manifest
# If you'd rather require your spec files manually (to control order for instance) you can disable the suite matcher in
# the configuration and use this file as a manifest.
#
# For more information: http://github.com/modeset/teaspoon
#
# You can require your own javascript files here. By default this will include everything in application, however you
# may get better load performance if you require the specific files that are being used in the spec that tests them.
#= require application
// Teaspoon includes some support files, but you can use anything from your own support path too.
// require support/jasmine-jquery
// require support/sinon
// require support/your-support-file
//
// PhantomJS (Teaspoons default driver) doesn't have support for Function.prototype.bind, which has caused confusion. Use
// this polyfill to avoid the confusion.
//= require support/bind-poly
//
// Deferring execution
// If you're using CommonJS, RequireJS or some other asynchronous library you can defer execution. Call Teaspoon.execute()
// after everything has been loaded. Simple example of a timeout:
//
// Teaspoon.defer = true
// setTimeout(Teaspoon.execute, 1000)
//
// Matching files
// By default Teaspoon will look for files that match _spec.{js,js.coffee,.coffee}. Add a filename_spec.js file in your
// spec path and it'll be included in the default suite automatically. If you want to customize suites, check out the
// configuration in config/initializers/teaspoon.rb
//
// Manifest
// If you'd rather require your spec files manually (to control order for instance) you can disable the suite matcher in
// the configuration and use this file as a manifest.
//
// For more information: http://github.com/modeset/teaspoon
//
// You can require javascript files here. A good place to start is by requiring your application.js.
//= require application
# == Schema Information
#
# Table name: comments
#
# id :integer not null, primary key
# author_id :integer
# post_id :integer
# body :text
# created_at :datetime
# updated_at :datetime
#
require 'spec_helper' require 'spec_helper'
describe Comment do describe Comment do
......
# == Schema Information
#
# Table name: posts
#
# id :integer not null, primary key
# title :string(255)
# body :text
# author_id :integer
# created_at :datetime
# updated_at :datetime
# is_draft :boolean default(FALSE)
# specified_date :date
#
require 'spec_helper' require 'spec_helper'
describe Post do describe Post do
......
# == Schema Information
#
# Table name: tags
#
# id :integer not null, primary key
# name :string(255)
# created_at :datetime
# updated_at :datetime
# ancestry :string(255)
# body :text
#
require 'spec_helper' require 'spec_helper'
describe Tag do describe Tag do
......
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# name :string(255)
# image_url :string(255)
# created_at :datetime
# updated_at :datetime
# email :string(255) default(""), not null
# encrypted_password :string(255) default(""), not null
# reset_password_token :string(255)
# reset_password_sent_at :datetime
# remember_created_at :datetime
# sign_in_count :integer default(0), not null
# current_sign_in_at :datetime
# last_sign_in_at :datetime
# current_sign_in_ip :string(255)
# last_sign_in_ip :string(255)
# google_auth_token :string(255)
# google_refresh_token :string(255)
# google_token_expires_at :datetime
# nickname :string(255) default(""), not null
#
require 'spec_helper' require 'spec_helper'
describe User do describe User do
......
# Set RAILS_ROOT and load the environment if it's not already loaded.
unless defined?(Rails)
ENV["RAILS_ROOT"] = File.expand_path("../../", __FILE__)
require File.expand_path("../../config/environment", __FILE__)
end
Teaspoon.configure do |config|
# Determines where the Teaspoon routes will be mounted. Changing this to "/jasmine" would allow you to browse to
# `http://localhost:3000/jasmine` to run your tests.
#config.mount_at = "/teaspoon"
# Specifies the root where Teaspoon will look for files. If you're testing an engine using a dummy application it can
# be useful to set this to your engines root (e.g. `Teaspoon::Engine.root`).
# Note: Defaults to `Rails.root` if nil.
#config.root = nil
# Paths that will be appended to the Rails assets paths
# Note: Relative to `config.root`.
#config.asset_paths = ["spec/javascripts", "spec/javascripts/stylesheets"]
# Fixtures are rendered through a controller, which allows using HAML, RABL/JBuilder, etc. Files in these paths will
# be rendered as fixtures.
#config.fixture_paths = ["spec/javascripts/fixtures"]
# SUITES
#
# You can modify the default suite configuration and create new suites here. Suites are isolated from one another.
#
# When defining a suite you can provide a name and a block. If the name is left blank, :default is assumed. You can
# omit various directives and the ones defined in the default suite will be used.
#
# To run a specific suite
# - in the browser: http://localhost/teaspoon/[suite_name]
# - with the rake task: rake teaspoon suite=[suite_name]
# - with the cli: teaspoon --suite=[suite_name]
config.suite do |suite|
# Specify the framework you would like to use. This allows you to select versions, and will do some basic setup for
# you -- which you can override with the directives below. This should be specified first, as it can override other
# directives.
# Note: If no version is specified, the latest is assumed.
#
# Available: jasmine[1.3.1, 2.0.0], mocha[1.10.0, 1.17.1] qunit[1.12.0, 1.14.0]
suite.use_framework :jasmine, "1.3.1"
# Specify a file matcher as a regular expression and all matching files will be loaded when the suite is run. These
# files need to be within an asset path. You can add asset paths using the `config.asset_paths`.
#suite.matcher = "{spec/javascripts,app/assets}/**/*_spec.{js,js.coffee,coffee}"
# This suites spec helper, which can require additional support files. This file is loaded before any of your test
# files are loaded.
#suite.helper = "spec_helper"
# The core Teaspoon javascripts. It's recommended to include only the base files here, as you can require support
# libraries from your spec helper.
# Note: For CoffeeScript files use `"teaspoon/jasmine"` etc.
#
# Available: teaspoon-jasmine, teaspoon-mocha, teaspoon-qunit
#suite.javascripts = ["jasmine/1.3.1", "teaspoon-jasmine"]
# You can include your own stylesheets if you want to change how Teaspoon looks.
# Note: Spec related CSS can and should be loaded using fixtures.
#suite.stylesheets = ["teaspoon"]
# Partial to be rendered in the head tag of the runner. You can use the provided ones or define your own by creating
# a `_boot.html.erb` in your fixtures path, and adjust the config to `"/boot"` for instance.
#
# Available: boot, boot_require_js
#suite.boot_partial = "boot"
# Partial to be rendered in the body tag of the runner. You can define your own to create a custom body structure.
#suite.body_partial = "body"
# Assets to be ignored when generating coverage reports. Accepts an array of filenames or regular expressions. The
# default excludes assets from vendor, gems and support libraries.<br/><br/>
#suite.no_coverage = [%r{/lib/ruby/gems/}, %r{/vendor/assets/}, %r{/support/}, %r{/(.+)_helper.}]
# Hooks allow you to use `Teaspoon.hook("fixtures")` before, after, or during your spec run. This will make a
# synchronous Ajax request to the server that will call all of the blocks you've defined for that hook name.
#suite.hook :fixtures, proc{ }
end
# Example suite. Since we're just filtering to files already within the root test/javascripts, these files will also
# be run in the default suite -- but can be focused into a more specific suite.
#config.suite :targeted do |suite|
# suite.matcher = "test/javascripts/targeted/*_test.{js,js.coffee,coffee}"
#end
# CONSOLE RUNNER SPECIFIC
#
# These configuration directives are applicable only when running via the rake task or command line interface. These
# directives can be overridden using the command line interface arguments or with ENV variables when using the rake
# task.
#
# Command Line Interface:
# teaspoon --driver=phantomjs --server-port=31337 --fail-fast=true --format=junit --suite=my_suite /spec/file_spec.js
#
# Rake:
# teaspoon DRIVER=phantomjs SERVER_PORT=31337 FAIL_FAST=true FORMATTERS=junit suite=my_suite
# Specify which headless driver to use. Supports PhantomJS and Selenium Webdriver.
#
# Available: phantomjs, selenium
# PhantomJS: https://github.com/modeset/teaspoon/wiki/Using-PhantomJS
# Selenium Webdriver: https://github.com/modeset/teaspoon/wiki/Using-Selenium-WebDriver
#config.driver = "phantomjs"
# Specify additional options for the driver.
#
# PhantomJS: https://github.com/modeset/teaspoon/wiki/Using-PhantomJS
# Selenium Webdriver: https://github.com/modeset/teaspoon/wiki/Using-Selenium-WebDriver
#config.driver_options = nil
# Specify the timeout for the driver. Specs are expected to complete within this time frame or the run will be
# considered a failure. This is to avoid issues that can arise where tests stall.
#config.driver_timeout = 180
# Specify a server to use with Rack (e.g. thin, mongrel). If nil is provided Rack::Server is used.
#config.server = nil
# Specify a port to run on a specific port, otherwise Teaspoon will use a random available port.
#config.server_port = nil
# Timeout for starting the server in seconds. If your server is slow to start you may have to bump this, or you may
# want to lower this if you know it shouldn't take long to start.
#config.server_timeout = 20
# Force Teaspoon to fail immediately after a failing suite. Can be useful to make Teaspoon fail early if you have
# several suites, but in environments like CI this may not be desirable.
#config.fail_fast = true
# Specify the formatters to use when outputting the results.
# Note: Output files can be specified by using `"junit>/path/to/output.xml"`.
#
# Available: dot, documentation, clean, json, junit, pride, snowday, swayze_or_oprah, tap, tap_y, teamcity
#config.formatters = ["dot"]
# Specify if you want color output from the formatters.
#config.color = true
# Teaspoon pipes all console[log/debug/error] to $stdout. This is useful to catch places where you've forgotten to
# remove them, but in verbose applications this may not be desirable.
#config.suppress_log = false
# COVERAGE REPORTS / THRESHOLD ASSERTIONS
#
# Coverage reports requires Istanbul (https://github.com/gotwarlost/istanbul) to add instrumentation to your code and
# display coverage statistics.
#
# Coverage configurations are similar to suites. You can define several, and use different ones under different
# conditions.
#
# To run with a specific coverage configuration
# - with the rake task: rake teaspoon USE_COVERAGE=[coverage_name]
# - with the cli: teaspoon --coverage=[coverage_name]
# Specify that you always want a coverage configuration to be used.
#config.use_coverage = nil
config.coverage do |coverage|
# Which coverage reports Instanbul should generate. Correlates directly to what Istanbul supports.
#
# Available: text-summary, text, html, lcov, lcovonly, cobertura, teamcity
#coverage.reports = ["text-summary", "html"]
# The path that the coverage should be written to - when there's an artifact to write to disk.
# Note: Relative to `config.root`.
#coverage.output_dir = "coverage"
# Various thresholds requirements can be defined, and those thresholds will be checked at the end of a run. If any
# aren't met the run will fail with a message. Thresholds can be defined as a percentage (0-100), or nil.
#coverage.statements = nil
#coverage.functions = nil
#coverage.branches = nil
#coverage.lines = nil
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment