├── .gitignore ├── .gitmodules ├── .rspec ├── Gemfile ├── Gemfile.lock ├── Rakefile ├── app ├── assets │ ├── images │ │ └── .keep │ ├── javascripts │ │ └── application.js │ └── stylesheets │ │ └── application.css.scss ├── controllers │ ├── admin │ │ ├── documents_controller.rb │ │ ├── pictures_controller.rb │ │ ├── sidekiq_controller.rb │ │ ├── users_controller.rb │ │ └── web_hooks_controller.rb │ ├── application_controller.rb │ ├── concerns │ │ └── .keep │ ├── documents_controller.rb │ ├── pictures_controller.rb │ ├── record_controller.rb │ ├── templates_controller.rb │ └── top_controller.rb ├── helpers │ ├── application_helper.rb │ └── devise_helper.rb ├── jobs │ ├── file_job.rb │ └── web_hook_job.rb ├── mailers │ └── .keep ├── models │ ├── .keep │ ├── concerns │ │ ├── .keep │ │ └── grade.rb │ ├── document.rb │ ├── picture.rb │ ├── template.rb │ ├── user.rb │ ├── user_document.rb │ └── web_hook.rb └── views │ ├── admin │ ├── documents │ │ ├── _list.html.slim │ │ ├── _modal.html.slim │ │ └── show.js.coffee │ ├── pictures │ │ ├── _delete.html.slim │ │ ├── _list.html.slim │ │ ├── _modal.html.slim │ │ ├── delete.js.coffee │ │ ├── index.html.slim │ │ └── show.js.coffee │ ├── sidekiq │ │ └── index.html.slim │ ├── users │ │ ├── _delete.html.slim │ │ ├── _form.html.slim │ │ ├── _list.html.slim │ │ ├── delete.js.coffee │ │ ├── edit.js.coffee │ │ ├── index.html.slim │ │ ├── new.js.coffee │ │ ├── show.html.slim │ │ └── submit.js.coffee │ └── web_hooks │ │ ├── _delete.html.slim │ │ ├── _form.html.slim │ │ ├── _list.html.slim │ │ ├── delete.js.coffee │ │ ├── edit.js.coffee │ │ ├── index.html.slim │ │ ├── new.js.coffee │ │ └── submit.js.coffee │ ├── devise │ ├── mailer │ │ └── reset_password_instructions.html.slim │ ├── passwords │ │ ├── edit.html.slim │ │ └── new.html.slim │ ├── registrations │ │ └── edit.html.slim │ └── sessions │ │ └── new.html.slim │ ├── documents │ ├── _delete.html.slim │ ├── _dropdown.html.slim │ ├── _form.html.slim │ ├── _list.html.slim │ ├── _sidebar.html.slim │ ├── delete.js.coffee │ ├── edit.html.slim │ ├── index.html.slim │ ├── new.html.slim │ ├── show.html.slim │ └── submit.js.coffee │ ├── error │ └── _form.html.slim │ ├── kaminari │ ├── _first_page.html.erb │ ├── _gap.html.erb │ ├── _last_page.html.erb │ ├── _next_page.html.erb │ ├── _page.html.erb │ ├── _paginator.html.erb │ └── _prev_page.html.erb │ ├── layouts │ └── application.html.slim │ ├── record │ ├── _dropdown.html.slim │ ├── _sidebar.html.slim │ └── index.html.slim │ ├── templates │ ├── _delete.html.slim │ ├── _form.html.slim │ ├── _list.html.slim │ ├── delete.js.coffee │ ├── edit.html.slim │ ├── index.html.slim │ ├── new.html.slim │ ├── select.js.coffee │ ├── show.html.slim │ └── submit.js.coffee │ └── top │ └── index.html.slim ├── bin ├── bundle ├── rails ├── rake ├── setup └── unicorn.j2 ├── config.ru ├── config ├── application.rb ├── boot.rb ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── events.rb ├── initializers │ ├── assets.rb │ ├── backtrace_silencers.rb │ ├── cookies_serializer.rb │ ├── devise.rb │ ├── filter_parameter_logging.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── multi_json.rb │ ├── session_store.rb │ ├── sidekiq.rb │ ├── websocket_rails.rb │ └── wrap_parameters.rb ├── locales │ ├── devise.en.yml │ ├── devise.ja.yml │ ├── en.yml │ └── ja.yml ├── nginx.j2 ├── routes.rb ├── secrets.yml ├── sidekiq.yml └── unicorn.rb ├── db ├── migrate │ ├── 20150109064610_devise_create_users.rb │ ├── 20150109120407_create_documents.rb │ ├── 20150109120656_create_user_documents.rb │ ├── 20150206085547_create_templates.rb │ ├── 20150303012227_create_pictures.rb │ ├── 20150303112317_add_admin_flag_to_users.rb │ ├── 20150409102507_add_grade_to_users.rb │ ├── 20150409141425_add_name_and_pattern_to_templtates.rb │ ├── 20150416101206_recoverable_users.rb │ ├── 20150422123551_create_web_hooks.rb │ └── 20150907074242_add_name_to_web_hooks.rb ├── schema.rb └── seeds.rb ├── lib ├── assets │ └── .keep ├── gitlab │ ├── popen.rb │ └── sidekiq_memory_killer.rb └── tasks │ ├── .keep │ ├── ansible.rake │ └── sidekiq.rake ├── log └── .keep ├── public ├── 404.html ├── 422.html ├── 500.html ├── fonts │ ├── logo_type_gothic.eot │ ├── logo_type_gothic.ttf │ └── logo_type_gothic.woff ├── images │ └── favicon.ico └── robots.txt ├── spec ├── controllers │ ├── admin │ │ ├── documents_controller_spec.rb │ │ ├── pictures_controller_spec.rb │ │ ├── sidekiq_controller_spec.rb │ │ ├── users_controller_spec.rb │ │ └── web_hooks_controller_spec.rb │ ├── documents_controller_spec.rb │ ├── pictures_controller_spec.rb │ ├── record_controller_spec.rb │ ├── templates_controller_spec.rb │ └── top_controller_spec.rb ├── factories │ ├── documents.rb │ ├── pictures.rb │ ├── templates.rb │ ├── user_documents.rb │ ├── users.rb │ └── web_hooks.rb ├── jobs │ ├── file_job_spec.rb │ └── web_hook_job_spec.rb ├── models │ ├── document_spec.rb │ ├── picture_spec.rb │ ├── template_spec.rb │ ├── user_document_spec.rb │ ├── user_spec.rb │ └── web_hook_spec.rb ├── rails_helper.rb └── spec_helper.rb └── vendor └── assets ├── javascripts ├── .keep ├── codemirror │ ├── addon │ │ └── mode │ │ │ └── overlay.js │ ├── codemirror.js │ └── mode │ │ ├── gfm │ │ └── gfm.js │ │ ├── markdown │ │ └── markdown.js │ │ └── xml │ │ └── xml.js ├── highlight │ └── highlight.min.js ├── marked │ └── marked.min.js └── uikit │ ├── components │ ├── accordion.min.js │ ├── autocomplete.min.js │ ├── datepicker.min.js │ ├── form-password.min.js │ ├── form-select.min.js │ ├── grid.min.js │ ├── htmleditor.min.js │ ├── lightbox.min.js │ ├── nestable.min.js │ ├── notify.min.js │ ├── pagination.min.js │ ├── parallax.min.js │ ├── search.min.js │ ├── slider.min.js │ ├── slideset.min.js │ ├── slideshow-fx.min.js │ ├── slideshow.min.js │ ├── sortable.min.js │ ├── sticky.min.js │ ├── timepicker.min.js │ ├── tooltip.min.js │ └── upload.min.js │ ├── core │ ├── alert.min.js │ ├── button.min.js │ ├── core.min.js │ ├── cover.min.js │ ├── dropdown.min.js │ ├── grid.min.js │ ├── modal.min.js │ ├── nav.min.js │ ├── offcanvas.min.js │ ├── scrollspy.min.js │ ├── smooth-scroll.min.js │ ├── switcher.min.js │ ├── tab.min.js │ ├── toggle.min.js │ ├── touch.min.js │ └── utility.min.js │ └── uikit.min.js └── stylesheets ├── .keep ├── codemirror └── codemirror.css ├── highlight └── tomorrow.css └── uikit ├── components ├── accordion.almost-flat.min.css ├── autocomplete.almost-flat.min.css ├── datepicker.almost-flat.min.css ├── dotnav.almost-flat.min.css ├── form-advanced.almost-flat.min.css ├── form-file.almost-flat.min.css ├── form-password.almost-flat.min.css ├── form-select.almost-flat.min.css ├── htmleditor.almost-flat.min.css ├── nestable.almost-flat.min.css ├── notify.almost-flat.min.css ├── placeholder.almost-flat.min.css ├── progress.almost-flat.min.css ├── search.almost-flat.min.css ├── slidenav.almost-flat.min.css ├── slider.almost-flat.min.css ├── slideshow.almost-flat.min.css ├── sortable.almost-flat.min.css ├── sticky.almost-flat.min.css ├── tooltip.almost-flat.min.css └── upload.almost-flat.min.css └── uikit.almost-flat.min.css /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | /vendor/bundler 10 | /vendor/bin 11 | 12 | # Ignore the default SQLite database. 13 | /db/*.sqlite3 14 | /db/*.sqlite3-journal 15 | 16 | # Ignore all logfiles and tempfiles. 17 | /log/*.log 18 | /tmp 19 | 20 | # Ignore editor swap files. 21 | *~ 22 | .*.swp 23 | *#* 24 | 25 | # Ignore assets pipeline files. 26 | /public/assets 27 | 28 | /public/pictures 29 | /public/documents 30 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "playbook"] 2 | path = playbook 3 | url = https://github.com/hico-horiuchi/ansible-rails-deploy.git 4 | [submodule "vendor/assets/stylesheets/github-markdown-css"] 5 | path = vendor/assets/stylesheets/github-markdown-css 6 | url = https://github.com/sindresorhus/github-markdown-css.git 7 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | ruby '2.2.3' 3 | 4 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' 5 | gem 'rails', '4.2.3' 6 | # Use postgresql as the database for Active Record 7 | gem 'pg' 8 | # Use SCSS for stylesheets 9 | gem 'sass-rails', '~> 5.0' 10 | # Use Uglifier as compressor for JavaScript assets 11 | gem 'uglifier', '>= 1.3.0' 12 | # Use CoffeeScript for .coffee assets and views 13 | gem 'coffee-rails', '~> 4.1.0' 14 | # See https://github.com/sstephenson/execjs#readme for more supported runtimes 15 | gem 'therubyracer', platforms: :ruby 16 | # Use jquery as the JavaScript library 17 | gem 'jquery-rails' 18 | # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks 19 | gem 'turbolinks' 20 | # jQuery plugin for drop-in fix binded events problem caused by Turbolinks 21 | gem 'jquery-turbolinks' 22 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder 23 | gem 'jbuilder', '~> 2.0' 24 | # Use ActiveModel has_secure_password 25 | # gem 'bcrypt', '~> 3.1.7' 26 | 27 | group :doc do 28 | # bundle exec rake doc:rails generates the API under doc/api. 29 | gem 'sdoc', '~> 0.4.0' 30 | end 31 | 32 | group :development do 33 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring 34 | gem 'spring' 35 | # Use Capistrano for deployment 36 | # gem 'capistrano-rails' 37 | gem 'annotate' 38 | gem 'quiet_assets' 39 | end 40 | 41 | group :development, :test do 42 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console 43 | # gem 'byebug' 44 | # Access an IRB console on exception pages or by using <%= console %> in views 45 | # gem 'web-console', '~> 2.0' 46 | gem 'pry-rails' 47 | gem 'rspec-rails' 48 | gem 'factory_girl_rails' 49 | gem 'better_errors' 50 | gem 'binding_of_caller' 51 | end 52 | 53 | group :production do 54 | # Use unicorn as the app server 55 | gem 'unicorn' 56 | gem 'unicorn-worker-killer' 57 | end 58 | 59 | gem 'yajl-ruby' 60 | gem 'devise' 61 | gem 'slim-rails' 62 | gem 'font-awesome-rails' 63 | gem 'kaminari' 64 | gem 'paperclip' 65 | gem 'websocket-rails' 66 | gem 'sidekiq' 67 | gem 'sinatra', require: false 68 | gem 'rmagick' 69 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sai-lab/shoko/bbe01346c725ee7342956c57f2295ce1e44636d6/app/assets/images/.keep -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. 9 | // 10 | // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require jquery 14 | //= require jquery.turbolinks 15 | //= require jquery_ujs 16 | //= require uikit/uikit.min 17 | //= require uikit/components/datepicker.min 18 | //= require uikit/components/htmleditor.min 19 | //= require uikit/components/notify.min 20 | //= require uikit/components/tooltip.min 21 | //= require uikit/components/upload.min 22 | //= require codemirror/codemirror 23 | //= require codemirror/mode/markdown/markdown 24 | //= require codemirror/mode/xml/xml 25 | //= require codemirror/mode/gfm/gfm 26 | //= require codemirror/addon/mode/overlay 27 | //= require marked/marked.min 28 | //= require highlight/highlight.min 29 | //= require websocket_rails/main 30 | //= require turbolinks 31 | -------------------------------------------------------------------------------- /app/controllers/admin/documents_controller.rb: -------------------------------------------------------------------------------- 1 | class Admin::DocumentsController < ApplicationController 2 | before_action :authenticate_user! 3 | before_action :admin_user! 4 | before_action :load_document 5 | 6 | def show 7 | end 8 | 9 | private 10 | 11 | def load_document 12 | @document = Document.id_is(params[:id]) if params[:id] 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/controllers/admin/pictures_controller.rb: -------------------------------------------------------------------------------- 1 | class Admin::PicturesController < ApplicationController 2 | before_action :authenticate_user! 3 | before_action :admin_user! 4 | before_action :load_picture 5 | 6 | def index 7 | @pictures = Picture.order(updated_at: :desc).page(params[:page]).per(20) 8 | end 9 | 10 | def show 11 | end 12 | 13 | def delete 14 | end 15 | 16 | def destroy 17 | @result = @picture.destroy 18 | 19 | if @result 20 | flash[:notice] = '画像を削除しました。' 21 | else 22 | flash[:alert] = '画像を削除できませんでした。' 23 | end 24 | 25 | redirect_to admin_pictures_path 26 | end 27 | 28 | private 29 | 30 | def load_picture 31 | @picture = Picture.id_is(params[:id]) if params[:id] 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /app/controllers/admin/sidekiq_controller.rb: -------------------------------------------------------------------------------- 1 | class Admin::SidekiqController < ApplicationController 2 | before_action :authenticate_user! 3 | before_action :admin_user! 4 | 5 | def index 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/controllers/admin/users_controller.rb: -------------------------------------------------------------------------------- 1 | class Admin::UsersController < ApplicationController 2 | before_action :authenticate_user! 3 | before_action :admin_user! 4 | before_action :load_user 5 | 6 | def index 7 | @users = User.order(updated_at: :desc).page(params[:page]).per(20) 8 | end 9 | 10 | def show 11 | @documents = @user.documents.order(updated_at: :desc).page(params[:page]).per(20) 12 | end 13 | 14 | def new 15 | @user = User.new 16 | end 17 | 18 | def create 19 | @user = User.new user_params 20 | @result = @user.save 21 | flash[:notice] = 'ユーザーを作成しました。' if @result 22 | render :submit 23 | end 24 | 25 | def edit 26 | end 27 | 28 | def update 29 | @result = @user.update_without_current_password user_params 30 | flash[:notice] = 'ユーザーを更新しました。' if @result 31 | render :submit 32 | end 33 | 34 | def delete 35 | end 36 | 37 | def destroy 38 | @result = @user.destroy 39 | 40 | if @result 41 | flash[:notice] = 'ユーザーを削除しました。' 42 | else 43 | flash[:alert] = 'ユーザーを削除できませんでした。' 44 | end 45 | 46 | redirect_to admin_users_path 47 | end 48 | 49 | private 50 | 51 | def load_user 52 | @user = User.id_is(params[:id]) if params[:id] 53 | end 54 | 55 | def user_params 56 | params.require(:user).permit :email, :name, :grade, :password, :password_confirmation, :admin_flag 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /app/controllers/admin/web_hooks_controller.rb: -------------------------------------------------------------------------------- 1 | class Admin::WebHooksController < ApplicationController 2 | before_action :authenticate_user! 3 | before_action :admin_user! 4 | before_action :load_web_hook 5 | 6 | def index 7 | @web_hooks = WebHook.order(updated_at: :desc).page(params[:page]).per(20) 8 | end 9 | 10 | def show 11 | end 12 | 13 | def new 14 | @web_hook = WebHook.new 15 | end 16 | 17 | def create 18 | @web_hook = WebHook.new web_hook_params 19 | @result = @web_hook.save 20 | flash[:notice] = 'WebHookを作成しました。' if @result 21 | render :submit 22 | end 23 | 24 | def edit 25 | end 26 | 27 | def update 28 | @result = @web_hook.update web_hook_params 29 | flash[:notice] = 'WebHookを更新しました。' if @result 30 | render :submit 31 | end 32 | 33 | def delete 34 | end 35 | 36 | def destroy 37 | @result = @web_hook.destroy 38 | 39 | if @result 40 | flash[:notice] = 'WebHookを削除しました。' 41 | else 42 | flash[:alert] = 'WebHookを削除できませんでした。' 43 | end 44 | 45 | redirect_to admin_web_hooks_path 46 | end 47 | 48 | private 49 | 50 | def load_web_hook 51 | @web_hook = WebHook.id_is(params[:id]) if params[:id] 52 | end 53 | 54 | def web_hook_params 55 | params.require(:web_hook).permit :name, :url 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | # Prevent CSRF attacks by raising an exception. 3 | # For APIs, you may want to use :null_session instead. 4 | protect_from_forgery with: :exception 5 | before_action :configure_permitted_parameters, if: :devise_controller? 6 | 7 | def admin_user! 8 | unless current_user.is_admin? 9 | render file: "#{Rails.root}/public/404.html", layout: false, status: 404 10 | end 11 | end 12 | 13 | def configure_permitted_parameters 14 | devise_parameter_sanitizer.for(:account_update) << [:email, :name] 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sai-lab/shoko/bbe01346c725ee7342956c57f2295ce1e44636d6/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /app/controllers/documents_controller.rb: -------------------------------------------------------------------------------- 1 | class DocumentsController < ApplicationController 2 | before_action :authenticate_user! 3 | before_action :load_document 4 | 5 | def index 6 | @users = User.all 7 | 8 | if params[:user].present? 9 | @documents = User.id_is(params[:user]).documents 10 | else 11 | @documents = Document.all 12 | end 13 | 14 | if params[:title].present? 15 | params[:title].split(' ').each do |title| 16 | @documents = @documents.search_title title 17 | end 18 | end 19 | 20 | if params[:keyword].present? 21 | params[:keyword].split(' ').each do |keyword| 22 | @documents = @documents.search_markdown keyword 23 | end 24 | end 25 | 26 | @documents = @documents.order(updated_at: :desc).page(params[:page]).per(10) 27 | end 28 | 29 | def show 30 | end 31 | 32 | def new 33 | @document = Document.new 34 | @templates = Template.order(:id).each do |template| 35 | template.replace_title current_user 36 | end 37 | end 38 | 39 | def create 40 | @document = Document.new document_params 41 | @result = @document.save 42 | 43 | if @result 44 | @document.user_documents.create user_id: current_user.id 45 | if @document.is_draft? 46 | flash[:notice] = 'ドキュメントを下書きしました。' 47 | else 48 | WebHookJob.perform_later current_user.id, @document.id, 'create' 49 | @document.create_markdown 50 | flash[:notice] = 'ドキュメントを公開しました。' 51 | end 52 | end 53 | 54 | render :submit 55 | end 56 | 57 | def edit 58 | @templates = Template.order(:id).each do |template| 59 | template.replace_title current_user 60 | end 61 | end 62 | 63 | def update 64 | old_title = @document.title 65 | was_draft = @document.is_draft? 66 | @result = @document.update document_params 67 | 68 | if @result 69 | unless @document.users.id_is(current_user.id) 70 | @document.user_documents.create user_id: current_user.id 71 | end 72 | 73 | if was_draft && @document.is_publish? 74 | WebHookJob.perform_later current_user.id, @document.id, 'create' 75 | @document.create_markdown 76 | elsif @document.is_publish? 77 | WebHookJob.perform_later current_user.id, @document.id, 'update' 78 | @document.update_markdown old_title 79 | end 80 | 81 | flash[:notice] = 'ドキュメントを更新しました。' 82 | end 83 | 84 | render :submit 85 | end 86 | 87 | def delete 88 | end 89 | 90 | def destroy 91 | @document.destroy_markdown 92 | @result = @document.destroy 93 | 94 | if @result 95 | flash[:notice] = 'ドキュメントを削除しました。' 96 | else 97 | flash[:alert] = 'ドキュメントを削除できませんでした。' 98 | end 99 | 100 | redirect_to documents_path 101 | end 102 | 103 | private 104 | 105 | def load_document 106 | @document = Document.id_is(params[:id]) if params[:id] 107 | end 108 | 109 | def document_params 110 | params.require(:document).permit :title, :markdown, :draft_flag 111 | end 112 | end 113 | -------------------------------------------------------------------------------- /app/controllers/pictures_controller.rb: -------------------------------------------------------------------------------- 1 | class PicturesController < ApplicationController 2 | before_action :authenticate_user! 3 | 4 | def create 5 | params[:files].each do |file| 6 | picture = Picture.new attachment: file 7 | 8 | if picture.save 9 | if picture.attachment_content_type == 'application/pdf' 10 | data = { 11 | image: picture.pdf_url, 12 | url: picture.attachment.url, 13 | file_name: picture.attachment_file_name 14 | } 15 | else 16 | data = { 17 | image: picture.attachment.url, 18 | url: picture.attachment.url, 19 | file_name: picture.attachment_file_name 20 | } 21 | end 22 | WebsocketRails[current_user.account].trigger :create_picture, data 23 | end 24 | end 25 | 26 | render nothing: true 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /app/controllers/record_controller.rb: -------------------------------------------------------------------------------- 1 | class RecordController < ApplicationController 2 | before_action :authenticate_user! 3 | 4 | def index 5 | @templates = Template.where.not(pattern: '') 6 | return unless params[:template].present? && params[:date].present? 7 | template = Template.id_is(params[:template]) 8 | 9 | date = Date.strptime(params[:date], '%y / %m / %d') 10 | date_str = date.strftime('%y%m%d') 11 | documents = Document.publish.search_title(template.name).search_title(date_str).includes(:users).order('users.grade desc', 'users.account asc') 12 | 13 | attends = {} 14 | outline_str = '' 15 | date_str = date.strftime("%Y.%m.%d(#{%w(日 月 火 水 木 金 土)[date.wday]})") 16 | 17 | documents.each do |document| 18 | user = document.users.last 19 | family_name = user.name.split(' ').first 20 | 21 | attends[user.grade] = [] unless attends[user.grade] 22 | attends[user.grade] << family_name 23 | 24 | matches = document.markdown.match(/#{template.pattern}/) 25 | outline_str += "○ #{family_name}\n\n" 26 | if matches 27 | outline_str += "#{matches[1]}\n\n" 28 | end 29 | end 30 | 31 | attend_str = '' 32 | attends.each do |grade, names| 33 | attend_str += "○ #{Grade::TEXT[grade]} #{names.join('、')}\n" 34 | end 35 | 36 | @record = "□ #{template.name}議事録 #{date_str}\n\n● 出席\n\n#{attend_str}\n● #{template.name}\n\n#{outline_str}".chomp 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /app/controllers/templates_controller.rb: -------------------------------------------------------------------------------- 1 | class TemplatesController < ApplicationController 2 | before_action :authenticate_user! 3 | before_action :load_template 4 | 5 | def index 6 | @templates = Template.order(updated_at: :desc).page(params[:page]).per(10) 7 | end 8 | 9 | def show 10 | end 11 | 12 | def new 13 | @template = Template.new 14 | end 15 | 16 | def create 17 | @template = Template.new template_params 18 | @result = @template.save 19 | flash[:notice] = 'テンプレートを作成しました。' if @result 20 | render :submit 21 | end 22 | 23 | def edit 24 | end 25 | 26 | def update 27 | @result = @template.update template_params 28 | flash[:notice] = 'テンプレートを更新しました。' if @result 29 | render :submit 30 | end 31 | 32 | def delete 33 | end 34 | 35 | def destroy 36 | @result = @template.destroy 37 | 38 | if @result 39 | flash[:notice] = 'テンプレートを削除しました。' 40 | else 41 | flash[:alert] = 'テンプレートを削除できませんでした。' 42 | end 43 | 44 | redirect_to templates_path 45 | end 46 | 47 | def select 48 | @template.replace_title current_user 49 | end 50 | 51 | private 52 | 53 | def load_template 54 | @template = Template.id_is(params[:id]) if params[:id] 55 | end 56 | 57 | def template_params 58 | params.require(:template).permit :name, :title, :markdown, :pattern 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /app/controllers/top_controller.rb: -------------------------------------------------------------------------------- 1 | class TopController < ApplicationController 2 | def index 3 | redirect_to documents_path if user_signed_in? 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/devise_helper.rb: -------------------------------------------------------------------------------- 1 | module DeviseHelper 2 | def devise_error_messages! 3 | return '' if resource.errors.empty? 4 | 5 | messages = resource.errors.full_messages.map { |msg| content_tag( :li, msg ) }.join 6 | sentence = I18n.t( 7 | 'errors.messages.not_saved', 8 | count: resource.errors.count, 9 | resource: resource.class.model_name.human.downcase 10 | ) 11 | 12 | html = sentence 13 | html.html_safe 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/jobs/file_job.rb: -------------------------------------------------------------------------------- 1 | class FileJob < ActiveJob::Base 2 | queue_as :file 3 | 4 | SAVE_DIR = "#{Rails.root}/public/documents" 5 | 6 | def perform(id, old_title) 7 | if old_title 8 | File.delete "#{SAVE_DIR}/#{old_title}.md" 9 | delete_dir_p old_title 10 | end 11 | 12 | if id 13 | document = Document.id_is id 14 | dir_path = get_dir_path document.title 15 | file_name = document.title.split('/').last 16 | 17 | FileUtils.mkdir_p dir_path 18 | write_file "#{dir_path}/#{file_name}.md", document.markdown 19 | end 20 | end 21 | 22 | def get_dir_path(title) 23 | dir = title.scan(/(.+)\/.+$/).flatten.first 24 | 25 | if dir 26 | return "#{SAVE_DIR}/#{dir}" 27 | else 28 | return SAVE_DIR 29 | end 30 | end 31 | 32 | def write_file(file_path, markdown) 33 | File.open(file_path, 'w') do |f| 34 | f.print markdown 35 | end 36 | end 37 | 38 | def delete_dir_p(old_title) 39 | dirs = old_title.split('/') 40 | dirs.pop 41 | 42 | while dirs.size > 0 43 | dir = "#{SAVE_DIR}/#{dirs.join '/'}" 44 | if Dir.entries(dir).join == '...' 45 | Dir.rmdir dir 46 | dirs.pop 47 | else 48 | break 49 | end 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /app/jobs/web_hook_job.rb: -------------------------------------------------------------------------------- 1 | class WebHookJob < ActiveJob::Base 2 | queue_as :web_hook 3 | 4 | def perform(user_id, document_id, action) 5 | user = User.id_is user_id 6 | document = Document.id_is document_id 7 | routes = Rails.application.routes.url_helpers 8 | action = { 9 | 'create' => '作成', 10 | 'update' => '更新' 11 | }[action] 12 | 13 | attachment = {} 14 | attachment[:fallback] = "#{user.name.split(' ').first}さんが「#{document.title}」を#{action}しました。" 15 | attachment[:title] = attachment[:fallback] 16 | attachment[:title_link] = routes.document_url document_id, host: `hostname -f`.chomp 17 | attachment[:text] = document.markdown.gsub(/!\[.+\]\(.+\)/, '').gsub(/\[(.+)\]\((.+)\)/, '<$2|$1>') 18 | attachment[:color] = '#9c9990' 19 | attachment[:mrkdwn_in] = ['text'] 20 | 21 | images = document.markdown.match(/!\[.+\]\((.+)\)/) 22 | attachment[:image_url] = images[1] if images 23 | 24 | payload = {} 25 | payload[:username] = '書庫' 26 | payload[:icon_emoji] = ':memo:' 27 | payload[:attachments] = [attachment] 28 | 29 | payload = payload.to_json 30 | 31 | WebHook.all.each do |web_hook| 32 | uri = URI.parse web_hook.url 33 | http = Net::HTTP.new uri.host, uri.port 34 | http.use_ssl = true if web_hook.url.include? 'https' 35 | 36 | request = Net::HTTP::Post.new uri.request_uri 37 | request['Content-Type'] = 'application/json' 38 | request.body = payload 39 | 40 | http.request request 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /app/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sai-lab/shoko/bbe01346c725ee7342956c57f2295ce1e44636d6/app/mailers/.keep -------------------------------------------------------------------------------- /app/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sai-lab/shoko/bbe01346c725ee7342956c57f2295ce1e44636d6/app/models/.keep -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sai-lab/shoko/bbe01346c725ee7342956c57f2295ce1e44636d6/app/models/concerns/.keep -------------------------------------------------------------------------------- /app/models/concerns/grade.rb: -------------------------------------------------------------------------------- 1 | module Grade 2 | TEXT = %w(TR B1 B2 B3 B4 M1 M2 D1 D2 D3) 3 | SELECT = [ 4 | ['TR', 0], 5 | ['B1', 1], ['B2', 2], ['B3', 3], ['B4', 4], 6 | ['M1', 5], ['M2', 6], 7 | ['D1', 7], ['D2', 8], ['D3', 9] 8 | ] 9 | 10 | def self.included(base) 11 | base.class_eval do 12 | validates :grade, inclusion: { in: 0..9 } 13 | 14 | public 15 | 16 | def grade_text 17 | TEXT[self.grade] 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/models/document.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: documents 4 | # 5 | # id :integer not null, primary key 6 | # title :string default(""), not null 7 | # markdown :text default(""), not null 8 | # draft_flag :boolean default(FALSE), not null 9 | # created_at :datetime not null 10 | # updated_at :datetime not null 11 | # 12 | 13 | class Document < ActiveRecord::Base 14 | validates_presence_of :title, :markdown 15 | 16 | has_many :user_documents, dependent: :destroy 17 | has_many :users, through: :user_documents 18 | 19 | scope :draft, -> { where(draft_flag: true) } 20 | scope :publish, -> { where(draft_flag: false) } 21 | scope :search_title, ->(keyword) { keyword ? Document.where(['title LIKE ?', "%#{PGconn.escape(keyword)}%"]) : Document.all } 22 | scope :search_markdown, ->(keyword) { keyword ? Document.where(['markdown LIKE ?', "%#{PGconn.escape(keyword)}%"]) : Document.all } 23 | 24 | def self.id_is(id) 25 | find_by(id: id.to_i) 26 | end 27 | 28 | def create_markdown 29 | FileJob.perform_later id, nil 30 | end 31 | 32 | def update_markdown(old_title) 33 | FileJob.perform_later id, old_title 34 | end 35 | 36 | def destroy_markdown 37 | FileJob.perform_later nil, title 38 | end 39 | 40 | def is_draft? 41 | draft_flag 42 | end 43 | 44 | def is_publish? 45 | !draft_flag 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /app/models/picture.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: pictures 4 | # 5 | # id :integer not null, primary key 6 | # attachment_file_name :string 7 | # attachment_content_type :string 8 | # attachment_file_size :integer 9 | # attachment_updated_at :datetime 10 | # created_at :datetime not null 11 | # updated_at :datetime not null 12 | # 13 | 14 | class Picture < ActiveRecord::Base 15 | has_attached_file :attachment, 16 | url: '/pictures/:hash.:extension', 17 | path: "#{Rails.root}/public/pictures/:hash.:extension", 18 | hash_secret: 'longSecretString' 19 | 20 | validates_attachment :attachment, 21 | presence: true, 22 | content_type: { content_type: /(image|application)\/(jpeg|png|gif|pdf)/ } 23 | 24 | def self.id_is(id) 25 | find_by(id: id.to_i) 26 | end 27 | 28 | def pdf_url 29 | image_path = attachment.url.gsub('.pdf', '.png') 30 | absolute_image_path = attachment.path.gsub('.pdf', '.png') 31 | return image_path if File.exists?(absolute_image_path) 32 | pdf = Magick::ImageList.new(attachment.path + '[0]') 33 | cover_tmp = absolute_image_path 34 | pdf[0].write(cover_tmp) 35 | image_path 36 | end 37 | 38 | def destroy 39 | destroy_pdf_image 40 | super 41 | end 42 | 43 | def destroy_pdf_image 44 | return unless attachment_content_type == 'application/pdf' 45 | file_path = attachment.path.gsub('.pdf', '.png') 46 | File.delete(file_path) if File.exists?(file_path) 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /app/models/template.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: templates 4 | # 5 | # id :integer not null, primary key 6 | # title :string default(""), not null 7 | # markdown :text default(""), not null 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # name :string default(""), not null 11 | # pattern :string default("") 12 | # 13 | 14 | class Template < ActiveRecord::Base 15 | validates_presence_of :name, :title, :markdown 16 | 17 | def self.id_is(id) 18 | find_by(id: id.to_i) 19 | end 20 | 21 | def replace_title(user) 22 | day = Time.now 23 | title.gsub! '%{year}', day.strftime('%y') 24 | title.gsub! '%{month}', day.strftime('%m') 25 | title.gsub! '%{day}', day.strftime('%d') 26 | title.gsub! '%{account}', user.account 27 | title.gsub! '%{name}', user.name 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: users 4 | # 5 | # id :integer not null, primary key 6 | # account :string default(""), not null 7 | # encrypted_password :string default(""), not null 8 | # name :string default(""), not null 9 | # created_at :datetime 10 | # updated_at :datetime 11 | # admin_flag :boolean default(FALSE), not null 12 | # grade :integer default(1), not null 13 | # email :string default(""), not null 14 | # reset_password_token :string 15 | # reset_password_sent_at :datetime 16 | # 17 | 18 | class User < ActiveRecord::Base 19 | devise :database_authenticatable, :registerable, :validatable, :recoverable 20 | validates_presence_of :name 21 | before_save :update_account! 22 | 23 | has_many :user_documents, dependent: :destroy 24 | has_many :documents, through: :user_documents 25 | 26 | include Grade 27 | 28 | def self.id_is(id) 29 | find_by(id: id.to_i) 30 | end 31 | 32 | def update_without_current_password(params, *options) 33 | params.delete(:current_password) 34 | params.delete(:password) if params[:password].blank? 35 | params.delete(:password_confirmation) if params[:password_confirmation].blank? 36 | 37 | clean_up_passwords 38 | update_attributes(params, *options) 39 | end 40 | 41 | def is_admin? 42 | admin_flag 43 | end 44 | 45 | private 46 | 47 | def update_account! 48 | self.account = email.match(/\A(.+)@/)[1] 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /app/models/user_document.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: user_documents 4 | # 5 | # id :integer not null, primary key 6 | # user_id :integer not null 7 | # document_id :integer not null 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # 11 | 12 | class UserDocument < ActiveRecord::Base 13 | belongs_to :user 14 | belongs_to :document 15 | end 16 | -------------------------------------------------------------------------------- /app/models/web_hook.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: web_hooks 4 | # 5 | # id :integer not null, primary key 6 | # url :string default(""), not null 7 | # created_at :datetime not null 8 | # updated_at :datetime not null 9 | # name :string default(""), not null 10 | # 11 | 12 | class WebHook < ActiveRecord::Base 13 | validates_presence_of :name, :url 14 | 15 | def self.id_is(id) 16 | find_by(id: id.to_i) 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/views/admin/documents/_list.html.slim: -------------------------------------------------------------------------------- 1 | - if documents.empty? 2 | .uk-alert.uk-alert-warning 3 | = fa_icon 'times', text: 'ドキュメントは存在しません。' 4 | 5 | - else 6 | .uk-overflow-container 7 | table.uk-table.uk-table-striped 8 | thead 9 | tr 10 | th style="width: 150px;" 11 | th.exo.exo-bold style="width: 300px;" ドキュメント 12 | th.exo.exo-bold style="width: 150px;" 最終更新日 13 | th.exo.exo-bold style="width: 50px;" 下書き 14 | th.exo.exo-bold Markdown 15 | tbody 16 | - documents.each do |document| 17 | tr 18 | td 19 | = link_to edit_document_path(document.id), class: 'uk-button uk-button-mini uk-button-success uk-margin-small-right' do 20 | = fa_icon 'pencil', text: '編集' 21 | = link_to delete_document_path(document.id), class: 'uk-button uk-button-mini uk-button-danger', remote: true do 22 | = fa_icon 'trash', text: '削除' 23 | td #{document.title} 24 | td #{I18n.l document.updated_at, format: :short} 25 | td.uk-text-center 26 | - if document.is_draft? 27 | = fa_icon 'check' 28 | td 29 | = link_to admin_document_path(document.id), remote: true do 30 | = fa_icon 'file-text-o', text: excerpt(document.markdown, '', radius: 25, omission: '…') 31 | -------------------------------------------------------------------------------- /app/views/admin/documents/_modal.html.slim: -------------------------------------------------------------------------------- 1 | .uk-modal-dialog.uk-modal-dialog-large 2 | a.uk-modal-close.uk-close 3 | #markdown 4 | 5 | javascript: 6 | markdown = '#{raw escape_javascript(document.markdown)}'; 7 | $('#markdown').html(marked(markdown, { breaks: true })); 8 | -------------------------------------------------------------------------------- /app/views/admin/documents/show.js.coffee: -------------------------------------------------------------------------------- 1 | $('.uk-modal').html('<%= escape_javascript(render partial: "admin/documents/modal", locals: { document: @document }) %>') 2 | UIkit.modal('.uk-modal').show() 3 | -------------------------------------------------------------------------------- /app/views/admin/pictures/_delete.html.slim: -------------------------------------------------------------------------------- 1 | .uk-modal-dialog 2 | a.uk-modal-close.uk-close 3 | 4 | .uk-modal-header 5 | h4.bold 6 | = fa_icon 'trash', text: '画像削除' 7 | 8 | | 「#{picture.attachment_file_name}」を削除しますか? 9 | 10 | .uk-modal-footer.uk-text-right 11 | .uk-button-group 12 | = link_to admin_picture_path, method: :delete, class: 'uk-button uk-button-danger' do 13 | = fa_icon 'trash', text: '削除' 14 | button.uk-button.uk-modal-close 15 | = fa_icon 'times', text: 'キャンセル' 16 | -------------------------------------------------------------------------------- /app/views/admin/pictures/_list.html.slim: -------------------------------------------------------------------------------- 1 | - if pictures.empty? 2 | .uk-alert.uk-alert-warning 3 | = fa_icon 'times', text: '画像は存在しません。' 4 | 5 | - else 6 | ul.uk-thumbnav.uk-grid-width-1-5 7 | - pictures.each do |picture| 8 | li 9 | - if picture.attachment_content_type == 'application/pdf' 10 | = link_to picture.attachment.url, target: :_blank 11 | .uk-thumbnail 12 | img src="#{picture.pdf_url}" alt="#{picture.attachment_file_name}" 13 | .uk-thumbnail-caption 14 | = link_to delete_admin_picture_path(picture.id), class: 'uk-button uk-button-danger uk-button-mini', remote: true 15 | = fa_icon 'trash', text: '削除' 16 | - else 17 | = link_to admin_picture_path(picture.id), remote: true do 18 | .uk-thumbnail 19 | img src="#{picture.attachment.url}" alt="#{picture.attachment_file_name}" 20 | .uk-thumbnail-caption 21 | = link_to delete_admin_picture_path(picture.id), class: 'uk-button uk-button-danger uk-button-mini', remote: true 22 | = fa_icon 'trash', text: '削除' 23 | -------------------------------------------------------------------------------- /app/views/admin/pictures/_modal.html.slim: -------------------------------------------------------------------------------- 1 | .uk-modal-dialog.uk-modal-dialog-large 2 | a.uk-modal-close.uk-close 3 | 4 | .uk-modal-header 5 | span.uk-h4.bold 6 | = fa_icon 'photo', text: picture.attachment_file_name 7 | span.uk-h6.uk-text-muted.uk-margin-small-left 8 | | (#{picture.attachment_content_type}) 9 | 10 | .uk-text-center 11 | img src="#{picture.attachment.url}" alt="#{picture.attachment_file_name}" 12 | 13 | .uk-modal-footer.uk-text-right 14 | button.uk-button.uk-modal-close 15 | = fa_icon 'times', text: '閉じる' 16 | -------------------------------------------------------------------------------- /app/views/admin/pictures/delete.js.coffee: -------------------------------------------------------------------------------- 1 | $('.uk-modal').html('<%= escape_javascript(render partial: "admin/pictures/delete", locals: { picture: @picture }) %>') 2 | UIkit.modal('.uk-modal').show() 3 | -------------------------------------------------------------------------------- /app/views/admin/pictures/index.html.slim: -------------------------------------------------------------------------------- 1 | - @title = '画像' 2 | 3 | h2.bold 4 | = fa_stacked_icon 'photo inverse', base: 'square', text: @title 5 | 6 | = render partial: 'admin/pictures/list', locals: { pictures: @pictures } 7 | = paginate @pictures 8 | 9 | coffee: 10 | $('#nav-admin').addClass('uk-active') 11 | -------------------------------------------------------------------------------- /app/views/admin/pictures/show.js.coffee: -------------------------------------------------------------------------------- 1 | $('.uk-modal').html('<%= escape_javascript(render partial: "admin/pictures/modal", locals: { picture: @picture }) %>') 2 | UIkit.modal('.uk-modal').show() 3 | -------------------------------------------------------------------------------- /app/views/admin/sidekiq/index.html.slim: -------------------------------------------------------------------------------- 1 | - @title = 'Sidekiq' 2 | 3 | h2.bold 4 | = fa_stacked_icon 'child inverse', base: 'square', text: @title 5 | 6 | iframe.uk-panel.uk-panel-box src="/sidekiq" 7 | 8 | coffee: 9 | $('#nav-admin').addClass('uk-active') 10 | -------------------------------------------------------------------------------- /app/views/admin/users/_delete.html.slim: -------------------------------------------------------------------------------- 1 | .uk-modal-dialog 2 | a.uk-modal-close.uk-close 3 | 4 | .uk-modal-header 5 | h4.bold 6 | = fa_icon 'trash', text: 'ユーザー削除' 7 | 8 | | 「#{user.account} (#{user.name})」を削除しますか? 9 | 10 | .uk-modal-footer.uk-text-right 11 | .uk-button-group 12 | = link_to admin_user_path, method: :delete, class: 'uk-button uk-button-danger' do 13 | = fa_icon 'trash', text: '削除' 14 | button.uk-button.uk-modal-close 15 | = fa_icon 'times', text: 'キャンセル' 16 | -------------------------------------------------------------------------------- /app/views/admin/users/_form.html.slim: -------------------------------------------------------------------------------- 1 | .uk-modal-dialog style="padding-bottom: 0" 2 | a.uk-modal-close.uk-close 3 | 4 | = form_for [:admin, user], html: { class: 'uk-form uk-form-stacked' }, remote: true do |f| 5 | .uk-modal-header 6 | h4.bold 7 | = fa_icon 'user', text: title 8 | 9 | .uk-form-row 10 | .uk-form-icon 11 | i.uk-icon-envelope 12 | = f.text_field :email, autofocus: true, placeholder: 'メールアドレス', style: 'padding-left: 30px;' 13 | .uk-form-help-block#user-email-error 14 | .uk-form-row 15 | .uk-form-icon 16 | i.uk-icon-font 17 | = f.text_field :name, placeholder: '名前', style: 'padding-left: 30px;' 18 | .uk-form-help-block#user-name-error 19 | .uk-form-row 20 | = f.select :grade, Grade::SELECT, {}, { class: 'uk-width-1-1' } 21 | .uk-form-help-block#user-grade-error 22 | .uk-form-row 23 | .uk-form-icon 24 | i.uk-icon-key 25 | = f.password_field :password, autocomplete: 'off', placeholder: 'パスワード', style: 'padding-left: 30px;' 26 | .uk-form-help-block#user-password-error 27 | .uk-form-row 28 | .uk-form-icon 29 | i.uk-icon-key 30 | = f.password_field :password_confirmation, autocomplete: 'off', placeholder: 'パスワード (確認)', style: 'padding-left: 30px;' 31 | .uk-form-help-block#user-password-confirmation-error 32 | .uk-form-row 33 | = f.check_box :admin_flag, class: 'uk-margin-left' 34 | = f.label :admin_flag, '管理者', class: 'uk-margin-left' 35 | 36 | .uk-modal-footer.uk-text-right 37 | .uk-button-group 38 | button.uk-button.uk-button-primary 39 | = fa_icon 'floppy-o', text: '保存' 40 | button.uk-button.uk-modal-close 41 | = fa_icon 'times', text: 'キャンセル' 42 | -------------------------------------------------------------------------------- /app/views/admin/users/_list.html.slim: -------------------------------------------------------------------------------- 1 | .uk-overflow-container 2 | table.uk-table.uk-table-striped 3 | thead 4 | tr 5 | th style="width: 150px;" 6 | = link_to new_admin_user_path, class: 'uk-button uk-button-mini uk-button-primary', remote: true do 7 | = fa_icon 'plus', text: '作成' 8 | th.bold style="width: 300px;" メールアドレス 9 | th.bold style="width: 150px;" 名前 10 | th.bold style="width: 50px;" 学年 11 | th.bold style="width: 50px;" 管理者 12 | th.bold ドキュメント 13 | tbody 14 | - users.includes(:documents).each do |user| 15 | tr 16 | td 17 | = link_to edit_admin_user_path(user.id), class: 'uk-button uk-button-mini uk-button-success uk-margin-small-right', remote: true do 18 | = fa_icon 'pencil', text: '編集' 19 | = link_to delete_admin_user_path(user.id), class: 'uk-button uk-button-mini uk-button-danger', remote: true do 20 | = fa_icon 'trash', text: '削除' 21 | td #{user.email} 22 | td #{user.name} 23 | td #{user.grade_text} 24 | td.uk-text-center 25 | - if user.is_admin? 26 | = fa_icon 'check' 27 | td 28 | = link_to admin_user_path(user.id) do 29 | = fa_icon 'files-o', text: "#{user.documents.size} ドキュメント" 30 | -------------------------------------------------------------------------------- /app/views/admin/users/delete.js.coffee: -------------------------------------------------------------------------------- 1 | $('.uk-modal').html('<%= escape_javascript(render partial: "admin/users/delete", locals: { user: @user }) %>') 2 | UIkit.modal('.uk-modal').show() 3 | -------------------------------------------------------------------------------- /app/views/admin/users/edit.js.coffee: -------------------------------------------------------------------------------- 1 | $('.uk-modal').html('<%= escape_javascript(render partial: "admin/users/form", locals: { user: @user, title: @user.account }) %>') 2 | UIkit.modal('.uk-modal').show() 3 | -------------------------------------------------------------------------------- /app/views/admin/users/index.html.slim: -------------------------------------------------------------------------------- 1 | - @title = 'ユーザー' 2 | 3 | h2.bold 4 | = fa_stacked_icon 'users inverse', base: 'square', text: @title 5 | 6 | = render partial: 'admin/users/list', locals: { users: @users } 7 | = paginate @users 8 | 9 | coffee: 10 | $('#nav-admin').addClass('uk-active') 11 | -------------------------------------------------------------------------------- /app/views/admin/users/new.js.coffee: -------------------------------------------------------------------------------- 1 | $('.uk-modal').html('<%= escape_javascript(render partial: "admin/users/form", locals: { user: @user, title: "ユーザー作成"}) %>') 2 | UIkit.modal('.uk-modal').show() 3 | -------------------------------------------------------------------------------- /app/views/admin/users/show.html.slim: -------------------------------------------------------------------------------- 1 | - @title = @user.account 2 | 3 | p 4 | span.uk-h2.bold 5 | = fa_stacked_icon 'user inverse', base: 'square', text: @title 6 | span.uk-h4.uk-text-muted.uk-margin-small-left 7 | | (#{@user.name}) 8 | 9 | = render partial: 'admin/documents/list', locals: { documents: @documents } 10 | = paginate @documents 11 | 12 | coffee: 13 | $('#nav-admin').addClass('uk-active') 14 | -------------------------------------------------------------------------------- /app/views/admin/users/submit.js.coffee: -------------------------------------------------------------------------------- 1 | <% if @user.errors.empty? %> 2 | location.reload(true) 3 | <% else %> 4 | $('[id^=user_]' ).removeClass('uk-form-danger') 5 | $('.uk-form-help-block').empty() 6 | <% if @user.errors.messages[:email] %> 7 | $('#user_email').addClass('uk-form-danger') 8 | $('#user-email-error').html('<%= escape_javascript(render partial: "error/form", locals: { label: "メールアドレス", messages: @user.errors.messages[:email] }) %>') 9 | <% end %> 10 | <% if @user.errors.messages[:name] %> 11 | $('#user_name').addClass('uk-form-danger') 12 | $('#user-name-error').html('<%= escape_javascript(render partial: "error/form", locals: { label: "名前", messages: @user.errors.messages[:name] }) %>') 13 | <% end %> 14 | <% if @user.errors.messages[:grade] %> 15 | $('#user_grade').addClass('uk-form-danger') 16 | $('#user-grade-error').html('<%= escape_javascript(render partial: "error/form", locals: { label: "学年", messages: @user.errors.messages[:grade] }) %>') 17 | <% end %> 18 | <% if @user.errors.messages[:password] %> 19 | $('#user_password').addClass('uk-form-danger') 20 | $('#user-password-error').html('<%= escape_javascript(render partial: "error/form", locals: { label: "パスワード", messages: @user.errors.messages[:password] }) %>') 21 | <% end %> 22 | <% if @user.errors.messages[:password_confirmation] %> 23 | $('#user_password_confirmation').addClass('uk-form-danger') 24 | $('#user-password-15~confirmation-error').html('<%= escape_javascript(render partial: "error/form", locals: { label: "確認のパスワード", messages: @user.errors.messages[:password_confirmation] }) %>') 25 | <% end %> 26 | <% end %> 27 | -------------------------------------------------------------------------------- /app/views/admin/web_hooks/_delete.html.slim: -------------------------------------------------------------------------------- 1 | .uk-modal-dialog 2 | a.uk-modal-close.uk-close 3 | 4 | .uk-modal-header 5 | h4.bold 6 | = fa_icon 'trash', text: 'WebHook削除' 7 | 8 | | 「#{web_hook.name}」を削除しますか? 9 | 10 | .uk-modal-footer.uk-text-right 11 | .uk-button-group 12 | = link_to admin_web_hook_path, method: :delete, class: 'uk-button uk-button-danger' do 13 | = fa_icon 'trash', text: '削除' 14 | button.uk-button.uk-modal-close 15 | = fa_icon 'times', text: 'キャンセル' 16 | -------------------------------------------------------------------------------- /app/views/admin/web_hooks/_form.html.slim: -------------------------------------------------------------------------------- 1 | .uk-modal-dialog style="padding-bottom: 0" 2 | a.uk-modal-close.uk-close 3 | 4 | = form_for [:admin, web_hook], html: { class: 'uk-form uk-form-stacked' }, remote: true do |f| 5 | .uk-modal-header 6 | h4.bold 7 | = fa_icon 'anchor', text: title 8 | 9 | .uk-form-row 10 | .uk-form-icon 11 | i.uk-icon-font 12 | = f.text_field :name, autofocus: true, placeholder: '名前', style: 'padding-left: 30px;' 13 | .uk-form-help-block#web_hook-name-error 14 | .uk-form-row 15 | .uk-form-icon 16 | i.uk-icon-link 17 | = f.text_field :url, placeholder: 'URL', style: 'padding-left: 30px;' 18 | .uk-form-help-block#web_hook-url-error 19 | 20 | .uk-modal-footer.uk-text-right 21 | .uk-button-group 22 | button.uk-button.uk-button-primary 23 | = fa_icon 'floppy-o', text: '保存' 24 | button.uk-button.uk-modal-close 25 | = fa_icon 'times', text: 'キャンセル' 26 | -------------------------------------------------------------------------------- /app/views/admin/web_hooks/_list.html.slim: -------------------------------------------------------------------------------- 1 | .uk-overflow-container 2 | table.uk-table.uk-table-striped 3 | thead 4 | tr 5 | th style="width: 150px;" 6 | = link_to new_admin_web_hook_path, class: 'uk-button uk-button-mini uk-button-primary', remote: true do 7 | = fa_icon 'plus', text: '作成' 8 | th.bold style="width: 150px;" 名前 9 | th.bold URL 10 | tbody 11 | - web_hooks.each do |web_hook| 12 | tr 13 | td 14 | = link_to edit_admin_web_hook_path(web_hook.id), class: 'uk-button uk-button-mini uk-button-success uk-margin-small-right', remote: true do 15 | = fa_icon 'pencil', text: '編集' 16 | = link_to delete_admin_web_hook_path(web_hook.id), class: 'uk-button uk-button-mini uk-button-danger', remote: true do 17 | = fa_icon 'trash', text: '削除' 18 | td #{web_hook.name} 19 | td #{web_hook.url} 20 | -------------------------------------------------------------------------------- /app/views/admin/web_hooks/delete.js.coffee: -------------------------------------------------------------------------------- 1 | $('.uk-modal').html('<%= escape_javascript(render partial: "admin/web_hooks/delete", locals: { web_hook: @web_hook }) %>') 2 | UIkit.modal('.uk-modal').show() 3 | -------------------------------------------------------------------------------- /app/views/admin/web_hooks/edit.js.coffee: -------------------------------------------------------------------------------- 1 | $('.uk-modal').html('<%= escape_javascript(render partial: "admin/web_hooks/form", locals: { web_hook: @web_hook, title: "WebHook編集" }) %>') 2 | UIkit.modal('.uk-modal').show() 3 | -------------------------------------------------------------------------------- /app/views/admin/web_hooks/index.html.slim: -------------------------------------------------------------------------------- 1 | - @title = 'WebHook' 2 | 3 | h2.bold 4 | = fa_stacked_icon 'slack inverse', base: 'square', text: @title 5 | 6 | = render partial: 'admin/web_hooks/list', locals: { web_hooks: @web_hooks } 7 | = paginate @web_hooks 8 | 9 | coffee: 10 | $('#nav-admin').addClass('uk-active') 11 | -------------------------------------------------------------------------------- /app/views/admin/web_hooks/new.js.coffee: -------------------------------------------------------------------------------- 1 | $('.uk-modal').html('<%= escape_javascript(render partial: "admin/web_hooks/form", locals: { web_hook: @web_hook, title: "WebHook作成"}) %>') 2 | UIkit.modal('.uk-modal').show() 3 | -------------------------------------------------------------------------------- /app/views/admin/web_hooks/submit.js.coffee: -------------------------------------------------------------------------------- 1 | <% if @web_hook.errors.empty? %> 2 | location.reload(true) 3 | <% else %> 4 | $('[id^=web-hook_]' ).removeClass('uk-form-danger') 5 | $('.uk-form-help-block').empty() 6 | <% if @web_hook.errors.messages[:name] %> 7 | $('#web_hook_name').addClass('uk-form-danger') 8 | $('#web_hook-name-error').html('<%= escape_javascript(render partial: "error/form", locals: { label: "名前", messages: @web_hook.errors.messages[:name] }) %>') 9 | <% end %> 10 | <% if @web_hook.errors.messages[:url] %> 11 | $('#web_hook_url').addClass('uk-form-danger') 12 | $('#web_hook-url-error').html('<%= escape_javascript(render partial: "error/form", locals: { label: "URL", messages: @web_hook.errors.messages[:url] }) %>') 13 | <% end %> 14 | <% end %> 15 | -------------------------------------------------------------------------------- /app/views/devise/mailer/reset_password_instructions.html.slim: -------------------------------------------------------------------------------- 1 | p 2 | | #{@resource.name} さん、こんにちは。 3 | br 4 | | 書庫をご利用いただきありがとうございます。 5 | 6 | p 7 | | パスワードリセットのリクエストが行われました。 8 | br 9 | | 以下のリンクをクリックして、パスワードを変更できます。 10 | 11 | p 12 | | #{edit_password_url( @resource, reset_password_token: @token )} 13 | 14 | p 15 | | もしあなたがパスワードリセットをリクエストしていない場合は、このメールを無視して下さい。 16 | br 17 | | 上記リンクをクリックして新しいパスワードを作成しない限り、パスワードは変更されません。 18 | 19 | p 20 | | (c) #{Shoko::Application.config.copyright} 21 | br 22 | | #{root_url} 23 | -------------------------------------------------------------------------------- /app/views/devise/passwords/edit.html.slim: -------------------------------------------------------------------------------- 1 | - @title = 'パスワードのリセット' 2 | - password_error = resource.errors.messages[:password].present? 3 | - password_confirmation_error = resource.errors.messages[:password_confirmation].present? 4 | 5 | .uk-width-medium-1-2.uk-container-center 6 | .uk-panel.uk-panel-box 7 | .uk-panel-title.bold 8 | = fa_icon 'key', text: @title 9 | 10 | .uk-nav-side 11 | .uk-nav-divider 12 | 13 | = form_for resource, as: resource_name, html: { class: 'uk-form uk-form-stacked', method: :put }, url: password_path(resource_name) do |f| 14 | = f.hidden_field :reset_password_token 15 | .uk-form-row 16 | .uk-form-icon 17 | i.uk-icon-key class="#{'uk-text-danger' if password_error}" 18 | = f.password_field :password, autofocus: true, autocomplete: 'off', placeholder: '新しいパスワード', style: 'padding-left: 30px;', class: "#{'uk-form-danger' if password_error}" 19 | - if password_error 20 | .uk-form-help-block 21 | = render partial: 'error/form', locals: { label: '新しいパスワード', messages: resource.errors.messages[:password] } 22 | .uk-form-row 23 | .uk-form-icon 24 | i.uk-icon-key class="#{'uk-text-danger' if password_confirmation_error}" 25 | = f.password_field :password_confirmation, autocomplete: 'off', placeholder: '新しいパスワード (確認)', style: 'padding-left: 30px;', class: "#{'uk-form-danger' if password_confirmation_error}" 26 | - if password_confirmation_error 27 | .uk-form-help-block 28 | = render partial: 'error/form', locals: { label: '確認のパスワード', messages: resource.errors.messages[:password_confirmation] } 29 | .uk-form-row 30 | .uk-button-group 31 | button.uk-button.uk-button-primary type="submit" 32 | = fa_icon 'refresh', text: 'リセット' 33 | = link_to new_user_session_path, class: 'uk-button' do 34 | = fa_icon 'sign-in', text: 'ログイン' 35 | 36 | - unless devise_error_messages!.empty? 37 | javascript: 38 | UIkit.notify({ message: '#{devise_error_messages!}', timeout: 3000, status: 'danger' }); 39 | -------------------------------------------------------------------------------- /app/views/devise/passwords/new.html.slim: -------------------------------------------------------------------------------- 1 | - @title = 'パスワードを忘れたら' 2 | - email_error = resource.errors.messages[:email].present? 3 | 4 | - unless devise_error_messages!.empty? 5 | javascript: 6 | UIkit.notify({ message: '#{devise_error_messages!}', timeout: 3000, status: 'danger' }); 7 | 8 | .uk-width-medium-1-2.uk-container-center 9 | .uk-panel.uk-panel-box 10 | .uk-panel-title.bold 11 | = fa_icon 'key', text: @title 12 | 13 | .uk-nav-side 14 | .uk-nav-divider 15 | 16 | = form_for resource, as: resource_name, html: { class: 'uk-form uk-form-stacked', method: :post }, url: password_path(resource_name) do |f| 17 | .uk-form-row 18 | .uk-form-icon 19 | i.uk-icon-envelope class="#{'uk-text-danger' if email_error}" 20 | = f.text_field :email, autofocus: true, placeholder: 'メールアドレス', style: 'padding-left: 30px;', class: "#{'uk-form-danger' if email_error}" 21 | .uk-form-help-block 22 | ul.uk-text-warning.fa-ul 23 | li = fa_icon 'li exclamation-triangle', text: 'パスワードの再設定に必要な情報を送信します。' 24 | - if email_error 25 | = render partial: 'error/form', locals: { label: 'メールアドレス', messages: resource.errors.messages[:email] } 26 | .uk-form-row 27 | .uk-button-group 28 | button.uk-button.uk-button-primary type="submit" 29 | = fa_icon 'paper-plane', text: '送信' 30 | = link_to new_user_session_path, class: 'uk-button' do 31 | = fa_icon 'sign-in', text: 'ログイン' 32 | -------------------------------------------------------------------------------- /app/views/devise/registrations/edit.html.slim: -------------------------------------------------------------------------------- 1 | - @title = '編集' 2 | - email_error = resource.errors.messages[:email].present? 3 | - name_error = resource.errors.messages[:name].present? 4 | - current_password_error = resource.errors.messages[:current_password].present? 5 | - password_error = resource.errors.messages[:password].present? 6 | - password_confirmation_error = resource.errors.messages[:password_confirmation].present? 7 | 8 | .uk-width-medium-1-2.uk-container-center 9 | .uk-panel.uk-panel-box 10 | .uk-panel-title.bold 11 | = fa_icon 'pencil', text: @title 12 | 13 | .uk-nav-side 14 | .uk-nav-divider 15 | 16 | = form_for resource, as: resource_name, html: { class: 'uk-form uk-form-stacked' }, url: registration_path(resource_name) do |f| 17 | .uk-form-row 18 | .uk-form-icon 19 | i.uk-icon-envelope class="#{'uk-text-danger' if email_error}" 20 | = f.text_field :email, autofocus: true, placeholder: 'メールアドレス', style: 'padding-left: 30px;', class: "#{'uk-form-danger' if email_error}" 21 | - if email_error 22 | .uk-form-help-block 23 | = render partial: 'error/form', locals: { label: 'メールアドレス', messages: resource.errors.messages[:email] } 24 | .uk-form-row 25 | .uk-form-icon 26 | i.uk-icon-user class="#{'uk-text-danger' if name_error}" 27 | = f.text_field :name, autofocus: true, placeholder: '名前', style: 'padding-left: 30px;', class: "#{'uk-form-danger' if name_error}" 28 | - if name_error 29 | .uk-form-help-block 30 | = render partial: 'error/form', locals: { label: '名前', messages: resource.errors.messages[:name] } 31 | .uk-form-row 32 | .uk-form-icon 33 | i.uk-icon-key class="#{'uk-text-danger' if current_password_error}" 34 | = f.password_field :current_password, autocomplete: 'off', placeholder: '現在のパスワード', style: 'padding-left: 30px;', class: "#{'uk-form-danger' if current_password_error}" 35 | - if current_password_error 36 | .uk-form-help-block 37 | = render partial: 'error/form', locals: { label: '現在のパスワード', messages: resource.errors.messages[:current_password] } 38 | .uk-form-row 39 | .uk-form-icon 40 | i.uk-icon-key class="#{'uk-text-danger' if password_error}" 41 | = f.password_field :password, autofocus: true, autocomplete: 'off', placeholder: '新しいパスワード', style: 'padding-left: 30px;', class: "#{'uk-form-danger' if password_error}" 42 | - if password_error 43 | .uk-form-help-block 44 | = render partial: 'error/form', locals: { label: '新しいパスワード', messages: resource.errors.messages[:password] } 45 | .uk-form-row 46 | .uk-form-icon 47 | i.uk-icon-key class="#{'uk-text-danger' if password_confirmation_error}" 48 | = f.password_field :password_confirmation, autocomplete: 'off', placeholder: '新しいパスワード (確認)', style: 'padding-left: 30px;', class: "#{'uk-form-danger' if password_confirmation_error}" 49 | - if password_confirmation_error 50 | .uk-form-help-block 51 | = render partial: 'error/form', locals: { label: '確認のパスワード', messages: resource.errors.messages[:password_confirmation] } 52 | .uk-form-row 53 | button.uk-button.uk-button-primary type="submit" 54 | = fa_icon 'floppy-o', text: '更新' 55 | 56 | - unless devise_error_messages!.empty? 57 | javascript: 58 | UIkit.notify({ message: '#{devise_error_messages!}', timeout: 3000, status: 'danger' }); 59 | 60 | coffee: 61 | $('#nav-user').addClass('uk-active') 62 | -------------------------------------------------------------------------------- /app/views/devise/sessions/new.html.slim: -------------------------------------------------------------------------------- 1 | - @title = 'ログイン' 2 | 3 | .uk-width-medium-1-2.uk-container-center 4 | .uk-panel.uk-panel-box 5 | .uk-panel-title.bold 6 | = fa_icon 'sign-in', text: @title 7 | 8 | .uk-nav-side 9 | .uk-nav-divider 10 | 11 | = form_for resource, as: resource_name, html: { class: 'uk-form uk-form-stacked' }, url: session_path(resource_name) do |f| 12 | .uk-form-row.uk-form-icon 13 | i.uk-icon-user 14 | = f.text_field :account, autofocus: true, placeholder: 'アカウント名' 15 | .uk-form-row.uk-form-icon 16 | i.uk-icon-key 17 | = f.password_field :password, autocomplete: 'off', placeholder: 'パスワード' 18 | .uk-form-row 19 | .uk-button-group 20 | button.uk-button.uk-button-primary type="submit" 21 | = fa_icon 'sign-in', text: 'ログイン' 22 | = link_to new_password_path(:user), class: 'uk-button' do 23 | = fa_icon 'key', text: 'パスワードを忘れたら' 24 | -------------------------------------------------------------------------------- /app/views/documents/_delete.html.slim: -------------------------------------------------------------------------------- 1 | .uk-modal-dialog 2 | a.uk-modal-close.uk-close 3 | 4 | .uk-modal-header 5 | h4.bold 6 | = fa_icon 'trash', text: 'ドキュメント削除' 7 | 8 | | 「#{document.title}」を削除しますか? 9 | 10 | .uk-modal-footer.uk-text-right 11 | .uk-button-group 12 | = link_to document_path, method: :delete, class: 'uk-button uk-button-danger' do 13 | = fa_icon 'trash', text: '削除' 14 | button.uk-button.uk-modal-close 15 | = fa_icon 'times', text: 'キャンセル' 16 | -------------------------------------------------------------------------------- /app/views/documents/_dropdown.html.slim: -------------------------------------------------------------------------------- 1 | .uk-button-dropdown data-uk-dropdown="{ mode: 'click' }" 2 | button.uk-button.uk-button-large.uk-button-primary 3 | = fa_icon 'search' 4 | 5 | .uk-dropdown 6 | = form_tag documents_path, method: :get, class: 'uk-form uk-form-stacked' do 7 | .uk-form-row 8 | = select_tag :user, options_from_collection_for_select(users, :id, :name), { prompt: 'ユーザー', class: 'uk-width-1-1' } 9 | .uk-form-row 10 | .uk-form-icon 11 | i.uk-icon-font 12 | = text_field_tag :title, params[:title], placeholder: 'タイトル' 13 | .uk-form-row 14 | .uk-form-icon 15 | i.uk-icon-paragraph 16 | = text_field_tag :keyword, params[:keyword], placeholder: 'キーワード' 17 | 18 | .uk-nav-side 19 | .uk-nav-divider 20 | 21 | .uk-form-row 22 | button.uk-button.uk-button-primary onClick="$('.uk-dropdown > .uk-form').submit()" 23 | = fa_icon 'search', text: '検索' 24 | -------------------------------------------------------------------------------- /app/views/documents/_list.html.slim: -------------------------------------------------------------------------------- 1 | - if documents.empty? 2 | .uk-alert.uk-alert-warning 3 | = fa_icon 'times', text: 'ドキュメントは存在しません。' 4 | 5 | - else 6 | dl.uk-description-list-line 7 | - documents.includes(:users).each do |document| 8 | dt 9 | = link_to document.title, document_path(document.id), class: 'uk-h3 uk-margin-right' 10 | - if document.is_draft? 11 | span.uk-text-muted.uk-margin-small-right data-uk-tooltip="" title="下書き" 12 | = fa_icon 'file' 13 | = link_to edit_document_path(document.id) do 14 | span.uk-text-success data-uk-tooltip="" title="編集" 15 | = fa_icon 'pencil' 16 | = link_to delete_document_path(document.id), remote: true do 17 | span.uk-text-danger.uk-margin-small-left data-uk-tooltip="" title="削除" 18 | = fa_icon 'trash' 19 | 20 | dd 21 | = fa_icon 'users' 22 | span.uk-margin-small-left #{document.users.pluck(:name).join(', ')} 23 | span.uk-margin-left 24 | = fa_icon 'calendar' 25 | span.uk-margin-small-left #{I18n.l document.updated_at, format: :short} 26 | 27 | - if params[:keyword].present? 28 | - keywords = params[:keyword].split ' ' 29 | dd 30 | = highlight excerpt(document.markdown, keywords.first, radius: 30, omission: ''), keywords 31 | -------------------------------------------------------------------------------- /app/views/documents/_sidebar.html.slim: -------------------------------------------------------------------------------- 1 | .uk-panel.uk-panel-box 2 | = form_tag documents_path, method: :get, class: 'uk-form uk-form-stacked' do 3 | .uk-panel-title.bold 4 | = fa_icon 'search', text: '検索' 5 | 6 | .uk-nav-side 7 | .uk-nav-divider 8 | 9 | .uk-form-row 10 | = select_tag :user, options_from_collection_for_select(users, :id, :name), { prompt: 'ユーザー', class: 'uk-width-1-1' } 11 | .uk-form-row 12 | .uk-form-icon 13 | i.uk-icon-font 14 | = text_field_tag :title, params[:title], placeholder: 'タイトル' 15 | .uk-form-row 16 | .uk-form-icon 17 | i.uk-icon-paragraph 18 | = text_field_tag :keyword, params[:keyword], placeholder: 'キーワード' 19 | 20 | .uk-nav-side 21 | .uk-nav-divider 22 | 23 | .uk-form-row 24 | button.uk-button.uk-button-primary onClick="$('.uk-panel > .uk-form').submit()" 25 | = fa_icon 'search', text: '検索' 26 | -------------------------------------------------------------------------------- /app/views/documents/delete.js.coffee: -------------------------------------------------------------------------------- 1 | $('.uk-modal').html('<%= escape_javascript(render partial: "documents/delete", locals: { document: @document }) %>') 2 | UIkit.modal('.uk-modal').show() 3 | -------------------------------------------------------------------------------- /app/views/documents/edit.html.slim: -------------------------------------------------------------------------------- 1 | - @title = 'ドキュメント編集' 2 | 3 | h2.bold 4 | = fa_stacked_icon 'file-text inverse', base: 'square', text: @title 5 | 6 | = render partial: 'documents/form', locals: { document: @document, templates: @templates } 7 | 8 | coffee: 9 | $('#nav-documents').addClass('uk-active') 10 | -------------------------------------------------------------------------------- /app/views/documents/index.html.slim: -------------------------------------------------------------------------------- 1 | - @title = 'ドキュメント' 2 | 3 | .relative 4 | h2.bold 5 | = fa_stacked_icon 'file-text inverse', base: 'square', text: @title 6 | .absolute-top.absolute-right.uk-visible-small 7 | = render partial: 'documents/dropdown', locals: { users: @users } 8 | 9 | .uk-grid 10 | .uk-width-medium-3-10 11 | .uk-hidden-small 12 | = render partial: 'documents/sidebar', locals: { users: @users } 13 | .uk-width-medium-7-10 14 | = render partial: 'documents/list', locals: { documents: @documents } 15 | = paginate @documents 16 | 17 | javascript: 18 | user = '#{params[:user]}' 19 | 20 | coffee: 21 | $('#nav-documents').addClass('uk-active') 22 | $('select#user').val(user) 23 | $('select#user').on 'change', -> 24 | if $(this).val() == '' 25 | $(this).addClass('placeholder') 26 | else 27 | $(this).removeClass('placeholder') 28 | $('select#user').change() 29 | -------------------------------------------------------------------------------- /app/views/documents/new.html.slim: -------------------------------------------------------------------------------- 1 | - @title = 'ドキュメント作成' 2 | 3 | h2.bold 4 | = fa_stacked_icon 'file-text inverse', base: 'square', text: @title 5 | 6 | = render partial: 'documents/form', locals: { document: @document, templates: @templates } 7 | 8 | coffee: 9 | $('#nav-documents').addClass('uk-active') 10 | -------------------------------------------------------------------------------- /app/views/documents/show.html.slim: -------------------------------------------------------------------------------- 1 | - @title = @document.title 2 | 3 | article.uk-article 4 | dd.uk-text-muted 5 | span.uk-article-title.uk-margin-right #{@document.title} 6 | - if @document.is_draft? 7 | span.uk-text-muted.uk-margin-small-right data-uk-tooltip="" title="下書き" 8 | = fa_icon 'file' 9 | = link_to edit_document_path do 10 | span.uk-text-success data-uk-tooltip="" title="編集" 11 | = fa_icon 'pencil' 12 | = link_to delete_document_path, remote: true do 13 | span.uk-text-danger.uk-margin-small-left data-uk-tooltip="" title="削除" 14 | = fa_icon 'trash' 15 | 16 | p 17 | = fa_icon 'users' 18 | span.uk-margin-small-left #{@document.users.pluck(:name).join(', ')} 19 | span.uk-margin-left 20 | = fa_icon 'calendar' 21 | span.uk-margin-small-left #{I18n.l @document.updated_at, format: :short} 22 | 23 | hr.uk-article-divider 24 | 25 | .markdown-body 26 | 27 | javascript: 28 | markdown = '#{raw escape_javascript(@document.markdown)}'; 29 | 30 | coffee: 31 | $('#nav-documents').addClass('uk-active') 32 | marked.setOptions { 33 | breaks: true 34 | gfm: true 35 | highlight: (code) -> 36 | return hljs.highlightAuto(code).value 37 | } 38 | $('.markdown-body').html marked(markdown) 39 | -------------------------------------------------------------------------------- /app/views/documents/submit.js.coffee: -------------------------------------------------------------------------------- 1 | <% if @result %> 2 | location.href = '/documents/<%= @document.id %>' 3 | <% else %> 4 | UIkit.notify({ message: 'タイトルと本文を入力してください。', timeout: 3000, status : 'danger' }) 5 | <% end %> 6 | -------------------------------------------------------------------------------- /app/views/error/_form.html.slim: -------------------------------------------------------------------------------- 1 | ul.uk-text-danger.fa-ul 2 | - messages.each do |message| 3 | li = fa_icon 'li times-circle', text: "#{label}#{message}" 4 | -------------------------------------------------------------------------------- /app/views/kaminari/_first_page.html.erb: -------------------------------------------------------------------------------- 1 | <% if current_page.first? %> 2 |
  • 3 | <%= raw(t 'views.pagination.first') %> 4 |
  • 5 | <% else %> 6 |
  • 7 | <%= link_to raw(t 'views.pagination.first'), url, remote: remote %> 8 |
  • 9 | <% end %> 10 | -------------------------------------------------------------------------------- /app/views/kaminari/_gap.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 | <%= link_to raw(t 'views.pagination.truncate'), '#' %> 3 |
  • 4 | -------------------------------------------------------------------------------- /app/views/kaminari/_last_page.html.erb: -------------------------------------------------------------------------------- 1 | <% if current_page.last? %> 2 |
  • 3 | <%= raw(t 'views.pagination.last') %> 4 |
  • 5 | <% else %> 6 |
  • 7 | <%= link_to raw(t 'views.pagination.last'), url, remote: remote %> 8 |
  • 9 | <% end %> 10 | -------------------------------------------------------------------------------- /app/views/kaminari/_next_page.html.erb: -------------------------------------------------------------------------------- 1 | <% if current_page.last? %> 2 |
  • 3 | <%= raw(t 'views.pagination.next') %> 4 |
  • 5 | <% else %> 6 |
  • 7 | <%= link_to raw(t 'views.pagination.next'), url, remote: remote %> 8 |
  • 9 | <% end %> 10 | -------------------------------------------------------------------------------- /app/views/kaminari/_page.html.erb: -------------------------------------------------------------------------------- 1 | <% if page.current? %> 2 |
  • 3 | <%= page %> 4 |
  • 5 | <% else %> 6 |
  • 7 | <%= link_to page, page.current? ? '#' : url, {remote: remote, rel: page.next? ? 'next' : page.prev? ? 'prev' : nil} %> 8 |
  • 9 | <% end %> 10 | -------------------------------------------------------------------------------- /app/views/kaminari/_paginator.html.erb: -------------------------------------------------------------------------------- 1 | <%= paginator.render do %> 2 | 15 | <% end %> 16 | -------------------------------------------------------------------------------- /app/views/kaminari/_prev_page.html.erb: -------------------------------------------------------------------------------- 1 | <% if current_page.first? %> 2 |
  • 3 | <%= raw(t 'views.pagination.previous') %> 4 |
  • 5 | <% else %> 6 |
  • 7 | <%= link_to raw(t 'views.pagination.previous'), url, remote: remote %> 8 |
  • 9 | <% end %> 10 | -------------------------------------------------------------------------------- /app/views/record/_dropdown.html.slim: -------------------------------------------------------------------------------- 1 | .uk-button-dropdown data-uk-dropdown="{ mode: 'click' }" 2 | button.uk-button.uk-button-large.uk-button-primary 3 | = fa_icon 'print' 4 | 5 | .uk-dropdown 6 | = form_tag record_index_path, method: :get, class: 'uk-form uk-form-stacked' do 7 | .uk-form-row 8 | = select_tag :template, options_from_collection_for_select(@templates, :id, :name), { prompt: 'テンプレート', class: 'uk-width-1-1' } 9 | .uk-form-row 10 | .uk-form-icon 11 | i.uk-icon-calendar 12 | = text_field_tag :date, params[:date], placeholder: '日付', readonly: true, 'data-uk-datepicker' => '{ format: "YY / MM / DD" }' 13 | 14 | .uk-nav-side 15 | .uk-nav-divider 16 | 17 | .uk-form-row 18 | button.uk-button.uk-button-medium.uk-button-primary onClick="$('.uk-dropdown > .uk-form').submit()" 19 | = fa_icon 'print', text: '生成' 20 | -------------------------------------------------------------------------------- /app/views/record/_sidebar.html.slim: -------------------------------------------------------------------------------- 1 | .uk-panel.uk-panel-box 2 | = form_tag record_index_path, method: :get, class: 'uk-form uk-form-stacked' do 3 | h3.uk-panel-title.bold 4 | = fa_icon 'print', text: '生成' 5 | 6 | .uk-nav-side 7 | .uk-nav-divider 8 | 9 | .uk-form-row 10 | = select_tag :template, options_from_collection_for_select(@templates, :id, :name), { prompt: 'テンプレート', class: 'uk-width-1-1' } 11 | .uk-form-row 12 | .uk-form-icon 13 | i.uk-icon-calendar 14 | = text_field_tag :date, params[:date], placeholder: '日付', readonly: true, 'data-uk-datepicker' => '{ format: "YY / MM / DD" }' 15 | 16 | .uk-nav-side 17 | .uk-nav-divider 18 | 19 | .uk-form-row 20 | button.uk-button.uk-button-medium.uk-button-primary onClick="$('.uk-panel > .uk-form').submit()" 21 | = fa_icon 'print', text: '生成' 22 | -------------------------------------------------------------------------------- /app/views/record/index.html.slim: -------------------------------------------------------------------------------- 1 | - @title = '議事録' 2 | 3 | .relative 4 | h2.bold 5 | = fa_stacked_icon 'leanpub inverse', base: 'square', text: @title 6 | .absolute-top.absolute-right.uk-visible-small 7 | = render partial: 'record/dropdown', locals: { templates: @templates } 8 | 9 | .uk-grid 10 | .uk-width-medium-3-10 11 | .uk-hidden-small 12 | = render partial: 'record/sidebar', locals: { templates: @templates } 13 | .uk-width-medium-7-10 14 | .uk-panel.uk-panel-box.monospace 15 | - if @record 16 | | #{simple_format @record} 17 | 18 | javascript: 19 | template = '#{params[:template]}' 20 | 21 | coffee: 22 | $('#nav-record').addClass('uk-active') 23 | $('select#template').val(template) 24 | $('select#template').on 'change', -> 25 | if $(this).val() == '' 26 | $(this).addClass('placeholder') 27 | else 28 | $(this).removeClass('placeholder') 29 | $('select#template').change() 30 | -------------------------------------------------------------------------------- /app/views/templates/_delete.html.slim: -------------------------------------------------------------------------------- 1 | .uk-modal-dialog 2 | a.uk-modal-close.uk-close 3 | 4 | .uk-modal-header 5 | h4.bold 6 | = fa_icon 'trash', text: 'テンプレート削除' 7 | 8 | | 「#{template.title}」を削除しますか? 9 | 10 | .uk-modal-footer.uk-text-right 11 | .uk-button-group 12 | = link_to template_path, method: :delete, class: 'uk-button uk-button-danger' do 13 | = fa_icon 'trash', text: '削除' 14 | button.uk-button.uk-modal-close 15 | = fa_icon 'times', text: 'キャンセル' 16 | -------------------------------------------------------------------------------- /app/views/templates/_form.html.slim: -------------------------------------------------------------------------------- 1 | = form_for template, html: { class: 'uk-form uk-form-stacked' }, remote: true do |f| 2 | .uk-form-row 3 | .uk-grid 4 | .uk-width-medium-1-3 5 | = f.text_field :name, autofocus: true, class: 'uk-form-large uk-width-1-1', placeholder: 'テンプレート名' 6 | .uk-margin-top.uk-visible-small 7 | .uk-width-medium-2-3 8 | = f.text_field :title, autofocus: true, class: 'uk-form-large uk-width-1-1', placeholder: 'ドキュメントタイトル' 9 | .uk-form-help-block 10 | ul.uk-text-warning.fa-ul 11 | li 12 | = fa_icon 'li exclamation-triangle' 13 | tt %{year} 14 | | (年)、 15 | tt %{month} 16 | | (月)、 17 | tt %{day} 18 | | (日)、 19 | tt %{account} 20 | | (アカウント名)、 21 | tt %{name} 22 | | (名前)が使えます。 23 | .uk-form-row 24 | = f.text_area :markdown, 'data-uk-htmleditor' => '{ markdown: true }' 25 | .uk-form-row 26 | .uk-grid 27 | .uk-width-medium-2-3 28 | = f.text_field :pattern, autofocus: true, class: 'uk-form-large uk-width-1-1', placeholder: '議事録生成用 正規表現 (グループ1つ含む)' 29 | .uk-margin-top.uk-visible-small 30 | .uk-width-medium-1-3.uk-text-center 31 | button.uk-button.uk-button-large.uk-button-primary style="width: 250px;" 32 | = fa_icon 'floppy-o', text: '保存' 33 | -------------------------------------------------------------------------------- /app/views/templates/_list.html.slim: -------------------------------------------------------------------------------- 1 | - if templates.empty? 2 | .uk-alert.uk-alert-warning 3 | = fa_icon 'times', text: 'テンプレートは存在しません。' 4 | 5 | - else 6 | dl.uk-description-list-line 7 | - templates.each do |template| 8 | dt 9 | = link_to template.name, template_path(template.id), class: 'uk-h3' 10 | span.uk-margin-small-left 11 | | (#{template.title}) 12 | = link_to edit_template_path(template.id) do 13 | span.uk-text-success.uk-margin-left data-uk-tooltip="" title="編集" 14 | = fa_icon 'pencil' 15 | = link_to delete_template_path(template.id), remote: true do 16 | span.uk-text-danger.uk-margin-small-left data-uk-tooltip="" title="削除" 17 | = fa_icon 'trash' 18 | 19 | dd 20 | = fa_icon 'calendar' 21 | span.uk-margin-small-left #{I18n.l template.updated_at, format: :short} 22 | -------------------------------------------------------------------------------- /app/views/templates/delete.js.coffee: -------------------------------------------------------------------------------- 1 | $('.uk-modal').html('<%= escape_javascript(render partial: "templates/delete", locals: { template: @template }) %>') 2 | UIkit.modal('.uk-modal').show() 3 | -------------------------------------------------------------------------------- /app/views/templates/edit.html.slim: -------------------------------------------------------------------------------- 1 | - @title = 'テンプレート編集' 2 | 3 | h2.bold 4 | = fa_stacked_icon 'file inverse', base: 'square', text: @title 5 | 6 | = render partial: 'templates/form', locals: { template: @template } 7 | 8 | coffee: 9 | $('#nav-templates').addClass('uk-active') 10 | -------------------------------------------------------------------------------- /app/views/templates/index.html.slim: -------------------------------------------------------------------------------- 1 | - @title = 'テンプレート' 2 | 3 | h2.bold 4 | = fa_stacked_icon 'file inverse', base: 'square', text: @title 5 | 6 | = render partial: 'templates/list', locals: { templates: @templates } 7 | = paginate @templates 8 | 9 | coffee: 10 | $('#nav-templates').addClass('uk-active') 11 | -------------------------------------------------------------------------------- /app/views/templates/new.html.slim: -------------------------------------------------------------------------------- 1 | - @title = 'テンプレート作成' 2 | 3 | h2.bold 4 | = fa_stacked_icon 'file inverse', base: 'square', text: @title 5 | 6 | = render partial: 'templates/form', locals: { template: @template } 7 | 8 | coffee: 9 | $('#nav-templates').addClass('uk-active') 10 | -------------------------------------------------------------------------------- /app/views/templates/select.js.coffee: -------------------------------------------------------------------------------- 1 | title = $('#document_title').val() 2 | if title == '' 3 | $('#document_title').val('<%= @template.title %>') 4 | else 5 | $('#document_title').val("#{title} <%= @template.title %>") 6 | markdown = $('#document_markdown').val() 7 | editor = $('.CodeMirror')[0].CodeMirror 8 | if markdown == '' 9 | editor.setValue('<%= raw escape_javascript(@template.markdown) %>') 10 | else 11 | editor.setValue("#{markdown}\n<%= escape_javascript @template.markdown %>") 12 | -------------------------------------------------------------------------------- /app/views/templates/show.html.slim: -------------------------------------------------------------------------------- 1 | - @title = @template.title 2 | 3 | article.uk-article 4 | dd.uk-text-muted 5 | span.uk-article-title #{@template.name} 6 | span.uk-margin-small-left 7 | | (#{@template.title}) 8 | = link_to edit_template_path do 9 | span.uk-text-success.uk-margin-left data-uk-tooltip="" title="編集" 10 | = fa_icon 'pencil' 11 | = link_to delete_template_path, remote: true do 12 | span.uk-text-danger.uk-margin-small-left data-uk-tooltip="" title="削除" 13 | = fa_icon 'trash' 14 | 15 | p 16 | = fa_icon 'calendar' 17 | span.uk-margin-small-left #{I18n.l @template.updated_at, format: :short} 18 | 19 | hr.uk-article-divider 20 | #markdown 21 | 22 | coffee: 23 | $('#nav-templates').addClass('uk-active') 24 | 25 | javascript: 26 | markdown = '#{raw escape_javascript(@template.markdown)}'; 27 | $('#markdown').html(marked(markdown, { breaks: true })); 28 | -------------------------------------------------------------------------------- /app/views/templates/submit.js.coffee: -------------------------------------------------------------------------------- 1 | <% if @result %> 2 | location.href = '/templates/<%= @template.id %>' 3 | <% else %> 4 | UIkit.notify({ message: '名前とタイトル、本文を入力してください。', timeout: 3000, status : 'danger' }) 5 | <% end %> 6 | -------------------------------------------------------------------------------- /app/views/top/index.html.slim: -------------------------------------------------------------------------------- 1 | - @title = 'ログイン' 2 | 3 | .uk-width-medium-1-2.uk-container-center 4 | .uk-panel.uk-panel-box 5 | .uk-panel-title.bold 6 | = fa_icon 'sign-in', text: @title 7 | 8 | .uk-nav-side 9 | .uk-nav-divider 10 | 11 | = form_for :user, html: { class: 'uk-form uk-form-stacked' }, url: { controller: 'devise/sessions', action: 'new' } do |f| 12 | .uk-form-row.uk-form-icon 13 | i.uk-icon-user 14 | = f.text_field :account, autofocus: true, placeholder: 'アカウント名', style: 'width: 80%;' 15 | .uk-form-row.uk-form-icon 16 | i.uk-icon-key 17 | = f.password_field :password, placeholder: 'パスワード', style: 'width: 80%;' 18 | .uk-form-row 19 | .uk-button-group 20 | button.uk-button.uk-button-primary type="submit" 21 | = fa_icon 'sign-in', text: 'ログイン' 22 | = link_to new_password_path(:user), class: 'uk-button' do 23 | = fa_icon 'key', text: 'パスワードを忘れたら' 24 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../../config/application', __FILE__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | 4 | # path to your application root. 5 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 6 | 7 | Dir.chdir APP_ROOT do 8 | # This script is a starting point to setup your application. 9 | # Add necessary setup steps to this file: 10 | 11 | puts "== Installing dependencies ==" 12 | system "gem install bundler --conservative" 13 | system "bundle check || bundle install" 14 | 15 | # puts "\n== Copying sample files ==" 16 | # unless File.exist?("config/database.yml") 17 | # system "cp config/database.yml.sample config/database.yml" 18 | # end 19 | 20 | puts "\n== Preparing database ==" 21 | system "bin/rake db:setup" 22 | 23 | puts "\n== Removing old logs and tempfiles ==" 24 | system "rm -f log/*" 25 | system "rm -rf tmp/cache" 26 | 27 | puts "\n== Restarting application server ==" 28 | system "touch tmp/restart.txt" 29 | end 30 | -------------------------------------------------------------------------------- /bin/unicorn.j2: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # http://xoxo-infra.hatenablog.com/entry/2013/04/25/173503 3 | 4 | set -e 5 | TIMEOUT=${TIMEOUT-60} 6 | APP_ROOT={{ dest }} 7 | PID=/tmp/unicorn.pid 8 | CMD="bundle exec unicorn -D -c $APP_ROOT/config/unicorn.rb" 9 | action="$1" 10 | set -u 11 | 12 | old_pid="$PID.oldbin" 13 | cd $APP_ROOT || exit 1 14 | 15 | sig () { 16 | test -s "$PID" && kill -$1 `cat $PID` 17 | } 18 | 19 | oldsig () { 20 | test -s $old_pid && kill -$1 `cat $old_pid` 21 | } 22 | 23 | case $action in 24 | start) 25 | sig 0 && echo >&2 "Already running" && exit 0 26 | $CMD 27 | ;; 28 | stop) 29 | sig QUIT && rm -f ${PID} && exit 0 30 | echo >&2 "Not running" 31 | ;; 32 | force-stop) 33 | sig TERM && exit 0 34 | echo >&2 "Not running" 35 | ;; 36 | restart|reload) 37 | sig HUP && echo reloaded OK && exit 0 38 | echo >&2 "Couldn't reload, starting '$CMD' instead" 39 | $CMD 40 | ;; 41 | upgrade) 42 | if sig USR2 && sleep 2 && sig 0 && oldsig QUIT 43 | then 44 | n=$TIMEOUT 45 | while test -s $old_pid && test $n -ge 0 46 | do 47 | printf '.' && sleep 1 && n=$(( $n - 1 )) 48 | done 49 | echo 50 | 51 | if test $n -lt 0 && test -s $old_pid 52 | then 53 | echo >&2 "$old_pid still exists after $TIMEOUT seconds" 54 | exit 1 55 | fi 56 | exit 0 57 | fi 58 | echo >&2 "Couldn't upgrade, starting '$CMD' instead" 59 | $CMD 60 | ;; 61 | reopen-logs) 62 | sig USR1 63 | ;; 64 | *) 65 | echo >&2 "Usage: $0 " 66 | exit 1 67 | ;; 68 | esac 69 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | if ENV['RACK_ENV'] == 'production' 4 | # Unicorn self-process killer 5 | require 'unicorn/worker_killer' 6 | 7 | # Max requests per worker 8 | use Unicorn::WorkerKiller::MaxRequests, 3072, 4096 9 | 10 | # Max memory size (RSS) per worker 11 | use Unicorn::WorkerKiller::Oom, (192*(1024**2)), (256*(1024**2)) 12 | end 13 | 14 | require ::File.expand_path('../config/environment', __FILE__) 15 | run Rails.application 16 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | require 'sidekiq/web' 5 | 6 | # Require the gems listed in Gemfile, including any gems 7 | # you've limited to :test, :development, or :production. 8 | Bundler.require(*Rails.groups) 9 | 10 | # http://easyramble.com/escape-like-on-rails-active-record.html 11 | module ActiveRecord 12 | class Base 13 | def self.escape_like(string) 14 | string.gsub(/[\\%_]/){ |m| "\\#{m}" } 15 | end 16 | end 17 | end 18 | 19 | module Shoko 20 | class Application < Rails::Application 21 | # Settings in config/environments/* take precedence over those specified here. 22 | # Application configuration should go into files in config/initializers 23 | # -- all .rb files in that directory are automatically loaded. 24 | 25 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 26 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 27 | # config.time_zone = 'Central Time (US & Canada)' 28 | config.time_zone = 'Tokyo' 29 | config.active_record.default_timezone = :local 30 | 31 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 32 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 33 | # config.i18n.default_locale = :de 34 | config.i18n.default_locale = :ja 35 | 36 | # Do not swallow errors in after_commit/after_rollback callbacks. 37 | config.active_record.raise_in_transactional_callbacks = true 38 | 39 | config.generators.template_engine = :slim 40 | config.generators.test_framework = :rspec 41 | config.generators.stylesheets = false 42 | config.generators.javascripts = false 43 | config.generators.helper = false 44 | 45 | config.middleware.delete 'Rack::Sendfile' 46 | config.autoload_paths += %W(#{config.root}/lib) 47 | config.active_job.queue_adapter = :sidekiq 48 | 49 | config.copyright = '香川大学 最所研究室' 50 | config.git_revision = `git log --abbrev-commit --pretty=oneline | head -1 | cut -d' ' -f1` 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | # PostgreSQL. Versions 8.2 and up are supported. 2 | # 3 | # Install the pg driver: 4 | # gem install pg 5 | # On OS X with Homebrew: 6 | # gem install pg -- --with-pg-config=/usr/local/bin/pg_config 7 | # On OS X with MacPorts: 8 | # gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config 9 | # On Windows: 10 | # gem install pg 11 | # Choose the win32 build. 12 | # Install PostgreSQL and put its /bin directory on your path. 13 | # 14 | # Configure Using Gemfile 15 | # gem 'pg' 16 | # 17 | default: &default 18 | adapter: postgresql 19 | encoding: unicode 20 | # For details on connection pooling, see rails configuration guide 21 | # http://guides.rubyonrails.org/configuring.html#database-pooling 22 | pool: 5 23 | # The specified database role being used to connect to postgres. 24 | # To create additional roles in postgres see `$ createuser --help`. 25 | # When left blank, postgres will use the default role. This is 26 | # the same name as the operating system user that initialized the database. 27 | username: shoko 28 | 29 | development: 30 | <<: *default 31 | database: shoko_development_<%= ENV['USER'] %> 32 | 33 | # The password associated with the postgres role (username). 34 | #password: 35 | 36 | # Connect on a TCP socket. Omitted by default since the client uses a 37 | # domain socket that doesn't need configuration. Windows does not have 38 | # domain sockets, so uncomment these lines. 39 | #host: localhost 40 | 41 | # The TCP port the server listens on. Defaults to 5432. 42 | # If your server runs on a different port number, change accordingly. 43 | #port: 5432 44 | 45 | # Schema search path. The server defaults to $user,public 46 | #schema_search_path: myapp,sharedapp,public 47 | 48 | # Minimum log levels, in increasing order: 49 | # debug5, debug4, debug3, debug2, debug1, 50 | # log, notice, warning, error, fatal, and panic 51 | # Defaults to warning. 52 | #min_messages: notice 53 | 54 | # Warning: The database defined as "test" will be erased and 55 | # re-generated from your development database when you run "rake". 56 | # Do not set this db to the same as development or production. 57 | test: 58 | <<: *default 59 | database: shoko_test_<%= ENV['USER'] %> 60 | 61 | # As with config/secrets.yml, you never want to store sensitive information, 62 | # like your database password, in your source code. If your source code is 63 | # ever seen by anyone, they now have access to your database. 64 | # 65 | # Instead, provide the password as a unix environment variable when you boot 66 | # the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database 67 | # for a full rundown on how to provide these environment variables in a 68 | # production deployment. 69 | # 70 | # On Heroku and other platform providers, you may have a full connection URL 71 | # available as an environment variable. For example: 72 | # 73 | # DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase" 74 | # 75 | # You can use this database configuration with: 76 | # 77 | # production: 78 | # url: <%= ENV['DATABASE_URL'] %> 79 | # 80 | production: 81 | <<: *default 82 | database: shoko_production 83 | password: <%= ENV['SHOKO_DATABASE_PASSWORD'] %> 84 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports and disable caching. 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send. 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger. 20 | config.active_support.deprecation = :log 21 | 22 | # Raise an error on page load if there are pending migrations. 23 | config.active_record.migration_error = :page_load 24 | 25 | # Debug mode disables concatenation and preprocessing of assets. 26 | # This option may cause significant delays in view rendering with a large 27 | # number of complex assets. 28 | config.assets.debug = true 29 | 30 | # Asset digests allow you to set far-future HTTP expiration dates on all assets, 31 | # yet still be able to expire them through the digest params. 32 | config.assets.digest = true 33 | 34 | # Adds additional error checking when serving assets at runtime. 35 | # Checks for improperly declared sprockets dependencies. 36 | # Raises helpful error messages. 37 | config.assets.raise_runtime_errors = true 38 | 39 | # Raises error for missing translations 40 | # config.action_view.raise_on_missing_translations = true 41 | 42 | config.action_mailer.default_url_options = { host: `hostname -f`.chomp } 43 | config.action_mailer.smtp_settings = { enable_starttls_auto: false } 44 | config.action_mailer.raise_delivery_errors = true 45 | 46 | config.middleware.delete Rack::Lock 47 | end 48 | 49 | BetterErrors::Middleware.allow_ip! '0.0.0.0' 50 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure static file server for tests with Cache-Control for performance. 16 | config.serve_static_files = true 17 | config.static_cache_control = 'public, max-age=3600' 18 | 19 | # Show full error reports and disable caching. 20 | config.consider_all_requests_local = true 21 | config.action_controller.perform_caching = false 22 | 23 | # Raise exceptions instead of rendering exception templates. 24 | config.action_dispatch.show_exceptions = false 25 | 26 | # Disable request forgery protection in test environment. 27 | config.action_controller.allow_forgery_protection = false 28 | 29 | # Tell Action Mailer not to deliver emails to the real world. 30 | # The :test delivery method accumulates sent emails in the 31 | # ActionMailer::Base.deliveries array. 32 | config.action_mailer.delivery_method = :test 33 | 34 | # Randomize the order test cases are executed. 35 | config.active_support.test_order = :random 36 | 37 | # Print deprecation notices to the stderr. 38 | config.active_support.deprecation = :stderr 39 | 40 | # Raises error for missing translations 41 | # config.action_view.raise_on_missing_translations = true 42 | end 43 | -------------------------------------------------------------------------------- /config/events.rb: -------------------------------------------------------------------------------- 1 | WebsocketRails::EventMap.describe do 2 | # You can use this file to map incoming events to controller actions. 3 | # One event can be mapped to any number of controller actions. The 4 | # actions will be executed in the order they were subscribed. 5 | # 6 | # Uncomment and edit the next line to handle the client connected event: 7 | # subscribe :client_connected, :to => Controller, :with_method => :method_name 8 | # 9 | # Here is an example of mapping namespaced events: 10 | # namespace :product do 11 | # subscribe :new, :to => ProductController, :with_method => :new_product 12 | # end 13 | # The above will handle an event triggered on the client like `product.new`. 14 | end 15 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 11 | # Rails.application.config.assets.precompile += %w( search.js ) 12 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.action_dispatch.cookies_serializer = :json 4 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /config/initializers/multi_json.rb: -------------------------------------------------------------------------------- 1 | require 'multi_json' 2 | MultiJson.use :yajl 3 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_shoko_session' 4 | -------------------------------------------------------------------------------- /config/initializers/sidekiq.rb: -------------------------------------------------------------------------------- 1 | REDIS_URL = { url: 'redis://localhost:6379', namespace: "sidekiq_#{ENV['USER']}" } 2 | 3 | Sidekiq.configure_server do |config| 4 | config.redis = REDIS_URL 5 | config.server_middleware do |chain| 6 | chain.add Sidekiq::Middleware::Server::RetryJobs, max_retries: 0 7 | # chain.add Gitlab::SidekiqMemoryKiller if ENV['SIDEKIQ_MEMORY_KILLER_MAX_RSS'] 8 | end 9 | end 10 | 11 | Sidekiq.configure_client do |config| 12 | config.redis = REDIS_URL 13 | end 14 | -------------------------------------------------------------------------------- /config/initializers/websocket_rails.rb: -------------------------------------------------------------------------------- 1 | WebsocketRails.setup do |config| 2 | # Change to true to enable standalone server mode 3 | # Start the standalone server with rake websocket_rails:start_server 4 | # * Requires Redis 5 | if Rails.env.production? 6 | config.standalone = true 7 | config.standalone_port = 3245 8 | else 9 | config.standalone = false 10 | end 11 | 12 | # Uncomment to override the default log level. The log level can be 13 | # any of the standard Logger log levels. By default it will mirror the 14 | # current Rails environment log level. 15 | # config.log_level = :debug 16 | 17 | # Uncomment to change the default log file path. 18 | # config.log_path = "#{Rails.root}/log/websocket_rails.log" 19 | 20 | # Set to true if you wish to log the internal websocket_rails events 21 | # such as the keepalive `websocket_rails.ping` event. 22 | # config.log_internal_events = false 23 | 24 | # Change to true to enable channel synchronization between 25 | # multiple server instances. 26 | # * Requires Redis. 27 | config.synchronize = false 28 | 29 | # Prevent Thin from daemonizing (default is true) 30 | # config.daemonize = false 31 | 32 | # Uncomment and edit to point to a different redis instance. 33 | # Will not be used unless standalone or synchronization mode 34 | # is enabled. 35 | # config.redis_options = {:host => 'localhost', :port => '6379'} 36 | 37 | # By default, all subscribers in to a channel will be removed 38 | # when that channel is made private. If you don't wish active 39 | # subscribers to be removed from a previously public channel 40 | # when making it private, set the following to true. 41 | # config.keep_subscribers_when_private = false 42 | 43 | # Set to true if you wish to broadcast channel subscriber_join and 44 | # subscriber_part events. All subscribers of a channel will be 45 | # notified when other clients join and part the channel. If you are 46 | # using the UserManager, the current_user object will be sent along 47 | # with the event. 48 | # config.broadcast_subscriber_events = true 49 | 50 | # Used as the key for the WebsocketRails.users Hash. This method 51 | # will be called on the `current_user` object in your controller 52 | # if one exists. If `current_user` does not exist or does not 53 | # respond to the identifier, the key will default to `connection.id` 54 | # config.user_identifier = :id 55 | 56 | # Uncomment and change this option to override the class associated 57 | # with your `current_user` object. This class will be used when 58 | # synchronization is enabled and you trigger events from background 59 | # jobs using the WebsocketRails.users UserManager. 60 | # config.user_class = User 61 | 62 | # Supporting HTTP streaming on Internet Explorer versions 8 & 9 63 | # requires CORS to be enabled for GET "/websocket" request. 64 | # List here the origin domains allowed to perform the request. 65 | # config.allowed_origins = ['http://localhost:3000'] 66 | 67 | end 68 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /config/locales/devise.ja.yml: -------------------------------------------------------------------------------- 1 | ja: 2 | devise: 3 | confirmations: 4 | confirmed: アカウントを登録しました。 5 | send_instructions: 登録方法を数分以内にメールでご連絡します。 6 | send_paranoid_instructions: メールアドレスが登録されていれば、数分以内にアカウントを確認する方法が記載されているメールが届きます。 7 | failure: 8 | already_authenticated: 既にログインしています。 9 | inactive: アカウントが復帰されていません。 10 | invalid: ログインIDまたはパスワードが違います。 11 | last_attempt: あと一回間違えるとアカウントが凍結されます。 12 | locked: アカウントが凍結されています。 13 | not_found_in_database: ログインIDまたはパスワードが違います。 14 | timeout: セッションがタイムアウトしました。もう一度ログインしてください。 15 | unauthenticated: 続けるにはログインまたはアカウントを登録してください。 16 | unconfirmed: 本登録を行ってください。 17 | mailer: 18 | confirmation_instructions: 19 | subject: アカウントの登録方法 20 | reset_password_instructions: 21 | subject: 【書庫】パスワードの再設定 22 | unlock_instructions: 23 | subject: アカウントの凍結解除 24 | omniauth_callbacks: 25 | failure: 「%{reason}」のため、%{kind}による認証ができませんでした。 26 | success: '%{kind}による認証に成功しました。' 27 | passwords: 28 | no_token: パスワード再設定のメール以外からこのページへアクセスする事はできません。もしパスワード再設定のメールに記載されたリンクをクリックしてこのページへ訪れた場合、不完全なURLのリンクをクリックしていないか確認してください。メーラーによっては、リンクのURLが途中で切れる可能性があります。 29 | send_instructions: パスワードの再設定方法を数分以内にメールでご連絡します。 30 | send_paranoid_instructions: メールアドレスが登録されていれば、数分以内にパスワード再設定のメールが届きます。 31 | updated: パスワードを変更し、ログインしました。 32 | updated_not_active: パスワードを変更しました。 33 | registrations: 34 | destroyed: アカウントを削除しました。またのご利用をお待ちしております。 35 | signed_up: アカウント登録を受け付けました。 36 | signed_up_but_inactive: 登録に成功しました。しかし、アカウントが有効になっていないためログインできません。 37 | signed_up_but_locked: 登録に成功しました。しかし、アカウントがロックされているためログインできません。 38 | signed_up_but_unconfirmed: アカウント確認のリンクが入っているメールを送りました。 メール内のリンクでアカウントを有効にしてください。 39 | update_needs_confirmation: アカウント情報を変更しました。しかし、メールアドレスを確認する必要があります。メール内のリンクで新しいメールアドレスを確認してください。 40 | updated: アカウント情報を更新しました。 41 | sessions: 42 | signed_in: ログインしました。 43 | signed_out: ログアウトしました。 44 | unlocks: 45 | send_instructions: アカウントの凍結解除方法を数分以内にメールでご連絡します。 46 | send_paranoid_instructions: アカウントが登録されていれば、数分以内にアカウントの凍結解除方法が登録しているアドレスに届きます。 47 | unlocked: アカウントを凍結解除しました。続けるにはログインしてください。 48 | errors: 49 | messages: 50 | already_confirmed: は既に登録済みです 51 | confirmation_period_expired: は%{period}以内に確認が必要です。もう一度要求してください。 52 | expired: は期限が切れたため、新しく取得する必要があります 53 | not_found: は見つかりませんでした 54 | not_locked: は凍結されていません 55 | not_saved: 'エラーが発生しました。以下の内容をご確認ください。' 56 | activerecord: 57 | errors: 58 | models: 59 | account: 60 | attributes: 61 | login_id: 62 | too_short: ログインIDが短すぎます。 63 | email: 64 | blank: メールアドレスが空欄です。 65 | invalid: メールアドレスが不正です。 66 | taken: 既に登録されているメールアドレスです。 67 | password: 68 | blank: パスワードが空欄です。 69 | too_short: パスワードが短すぎます。 70 | password_confirmation: 71 | confirmation: パスワードの確認が一致しません。 -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /config/nginx.j2: -------------------------------------------------------------------------------- 1 | upstream unicorn { 2 | server unix:/tmp/unicorn.sock 3 | fail_timeout=0; 4 | } 5 | 6 | server { 7 | listen 80; 8 | server_name {{ ansible_fqdn }}; 9 | return 301 https://$host$request_uri; 10 | } 11 | 12 | server { 13 | listen 443; 14 | ssl on; 15 | ssl_prefer_server_ciphers on; 16 | ssl_certificate /etc/nginx/ssl/{{ ansible_hostname }}.crt; 17 | ssl_certificate_key /etc/nginx/ssl/{{ ansible_hostname }}.key; 18 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 19 | 20 | server_name {{ ansible_fqdn }}; 21 | client_max_body_size 4G; 22 | keepalive_timeout 5; 23 | root {{ dest }}/public; 24 | 25 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 26 | '$status $body_bytes_sent "$http_referer" ' 27 | '"$http_user_agent" "$http_x_forwarded_for" $request_time'; 28 | access_log /var/log/nginx/access.log main; 29 | 30 | location /websocket { 31 | proxy_pass http://localhost:3245/websocket; 32 | proxy_http_version 1.1; 33 | proxy_set_header Upgrade $http_upgrade; 34 | proxy_set_header Connection Upgrade; 35 | proxy_set_header X-Real-IP $remote_addr; 36 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 37 | } 38 | 39 | location ~ ^/(assets|images|fonts|pictures)/ { 40 | root {{ dest }}/public; 41 | } 42 | 43 | location / { 44 | proxy_set_header X-Real-IP $remote_addr; 45 | proxy_set_header X-Forwarded-Proto $scheme; 46 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 47 | proxy_set_header Host $http_host; 48 | proxy_pass http://unicorn; 49 | } 50 | 51 | error_page 403 404 /404.html; 52 | location = /404.html { 53 | root {{ dest }}/public; 54 | } 55 | 56 | error_page 422 /422.html; 57 | location = /422.html { 58 | root {{ dest }}/public; 59 | } 60 | 61 | error_page 500 502 503 504 /500.html; 62 | location = /500.html { 63 | root {{ dest }}/public; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | root to: 'top#index' 3 | 4 | devise_for :users 5 | 6 | resources :documents do 7 | get :delete, on: :member 8 | end 9 | 10 | resources :templates do 11 | get :delete, on: :member 12 | get :select, on: :member 13 | end 14 | 15 | resources :pictures, only: [:create] 16 | 17 | resources :record, only: [:index] 18 | 19 | namespace :admin do 20 | resources :users do 21 | get :delete, on: :member 22 | end 23 | 24 | resources :documents, only: [:show] 25 | 26 | resources :pictures, only: [:index, :show, :destroy] do 27 | get :delete, on: :member 28 | end 29 | 30 | resources :web_hooks, except: [:show] do 31 | get :delete, on: :member 32 | end 33 | 34 | resources :sidekiq, only: %w( index ) 35 | end 36 | 37 | authenticate :user, lambda { |u| u.is_admin? } do 38 | mount Sidekiq::Web => '/sidekiq' 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rake secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: 7e5d751d0047aea042e58d102d774ad4a7cae45c9bd59591b7f2312934cab93500f7c4da9452bc37de085d77e92ba6f0f61197aae736ac75ab56dfea5071afca 15 | 16 | test: 17 | secret_key_base: 3fc95be32dd678228fc8ed2c8cc29f62171f1b2cb169243fe157792ff393fd365ca2997269410956c9bd2f359e09c25a56d94b9877893b879ddf3afbe226b8d9 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 23 | -------------------------------------------------------------------------------- /config/sidekiq.yml: -------------------------------------------------------------------------------- 1 | :verbose: false 2 | :daemon: true 3 | :pidfile: ./tmp/pids/sidekiq.pid 4 | :logfile: ./log/sidekiq.log 5 | :concurrency: 1 6 | :queues: 7 | - file 8 | - web_hook 9 | -------------------------------------------------------------------------------- /config/unicorn.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # ワーカーの数 3 | worker_processes 2 4 | 5 | # タイムアウト 6 | timeout 15 7 | 8 | # ソケット 9 | listen '/tmp/unicorn.sock' 10 | pid '/tmp/unicorn.pid' 11 | 12 | # ログ 13 | log = '/var/log/rails/unicorn.log' 14 | stderr_path File.expand_path( 'log/unicorn.log', ENV['RAILS_ROOT'] ) 15 | stdout_path File.expand_path( 'log/unicorn.log', ENV['RAILS_ROOT'] ) 16 | 17 | preload_app true 18 | GC.respond_to?( :copy_on_write_friendly= ) and GC.copy_on_write_friendly = true 19 | 20 | before_fork do |server, worker| 21 | defined?( ActiveRecord::Base ) and ActiveRecord::Base.connection.disconnect! 22 | 23 | old_pid = "#{server.config[:pid]}.oldbin" 24 | unless old_pid == server.pid 25 | begin 26 | Process.kill :QUIT, File.read( old_pid ).to_i 27 | rescue Errno::ENOENT, Errno::ESRCH 28 | end 29 | end 30 | end 31 | 32 | after_fork do |server, worker| 33 | defined?( ActiveRecord::Base ) and ActiveRecord::Base.establish_connection 34 | end 35 | -------------------------------------------------------------------------------- /db/migrate/20150109064610_devise_create_users.rb: -------------------------------------------------------------------------------- 1 | class DeviseCreateUsers < ActiveRecord::Migration 2 | def change 3 | create_table(:users) do |t| 4 | t.string :account, null: false, default: "" 5 | t.string :encrypted_password, null: false, default: "" 6 | t.string :name, null: false, default: "" 7 | 8 | t.timestamps 9 | end 10 | 11 | add_index :users, :account, unique: true 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20150109120407_create_documents.rb: -------------------------------------------------------------------------------- 1 | class CreateDocuments < ActiveRecord::Migration 2 | def change 3 | create_table :documents do |t| 4 | t.string :title, null: false, default: "" 5 | t.text :markdown, null: false, default: "" 6 | t.boolean :draft_flag, null: false, default: false 7 | 8 | t.timestamps null: false 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20150109120656_create_user_documents.rb: -------------------------------------------------------------------------------- 1 | class CreateUserDocuments < ActiveRecord::Migration 2 | def change 3 | create_table :user_documents do |t| 4 | t.references :user, index: true, null: false 5 | t.references :document, index: true, null: false 6 | 7 | t.timestamps null: false 8 | end 9 | 10 | add_foreign_key :user_documents, :users 11 | add_foreign_key :user_documents, :documents 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20150206085547_create_templates.rb: -------------------------------------------------------------------------------- 1 | class CreateTemplates < ActiveRecord::Migration 2 | def change 3 | create_table :templates do |t| 4 | t.string :title, null: false, default: "" 5 | t.text :markdown, null: false, default: "" 6 | 7 | t.timestamps null: false 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20150303012227_create_pictures.rb: -------------------------------------------------------------------------------- 1 | class CreatePictures < ActiveRecord::Migration 2 | def change 3 | create_table :pictures do |t| 4 | t.attachment :attachment 5 | t.timestamps null: false 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20150303112317_add_admin_flag_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddAdminFlagToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :admin_flag, :boolean, null: false, default: false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20150409102507_add_grade_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddGradeToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :grade, :int, null: false, default: 1 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20150409141425_add_name_and_pattern_to_templtates.rb: -------------------------------------------------------------------------------- 1 | class AddNameAndPatternToTempltates < ActiveRecord::Migration 2 | def change 3 | add_column :templates, :name, :string, null: false, default: "" 4 | add_column :templates, :pattern, :string, default: "" 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20150416101206_recoverable_users.rb: -------------------------------------------------------------------------------- 1 | class RecoverableUsers < ActiveRecord::Migration 2 | def up 3 | add_column :users, :email, :string, null: false, default: "" 4 | add_column :users, :reset_password_token, :string 5 | add_column :users, :reset_password_sent_at, :datetime 6 | 7 | User.all.each do |user| 8 | if user.email.empty? 9 | user.update email: "#{user.account}@example.com" 10 | end 11 | end 12 | 13 | add_index :users, :email, unique: true 14 | end 15 | 16 | def down 17 | remove_column :users, :email 18 | remove_column :users, :reset_password_token 19 | remove_column :users, :reset_password_sent_at 20 | 21 | remove_index :users, :email 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /db/migrate/20150422123551_create_web_hooks.rb: -------------------------------------------------------------------------------- 1 | class CreateWebHooks < ActiveRecord::Migration 2 | def change 3 | create_table :web_hooks do |t| 4 | t.string :url, null: false, default: "" 5 | 6 | t.timestamps null: false 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20150907074242_add_name_to_web_hooks.rb: -------------------------------------------------------------------------------- 1 | class AddNameToWebHooks < ActiveRecord::Migration 2 | def change 3 | add_column :web_hooks, :name, :string, null: false, default: "" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | 9 | User.create email: 'shoko-admin@example.com', name: '書庫管理者', admin_flag: true, password: 'password', password_confirmation: 'password' 10 | print "\e[31m!! shoko-admin : password !!\e[0m\n" 11 | 12 | Template.create( 13 | title: '週間報告/%{account}/%{year}%{month}%{day}', 14 | markdown: "## 活動概要\r\n\r\n\r\n\r\n## 研究活動\r\n\r\n\r\n\r\n", 15 | name: '週間報告', 16 | pattern: '## 活動概要\\r\\n\\r\\n([\\s\\S]*)\\r\\n\\r\\n## 研究活動' 17 | ) 18 | -------------------------------------------------------------------------------- /lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sai-lab/shoko/bbe01346c725ee7342956c57f2295ce1e44636d6/lib/assets/.keep -------------------------------------------------------------------------------- /lib/gitlab/popen.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | require 'open3' 3 | 4 | module Gitlab 5 | module Popen 6 | extend self 7 | 8 | def popen(cmd, path=nil) 9 | unless cmd.is_a?(Array) 10 | raise "System commands must be given as an array of strings" 11 | end 12 | 13 | path ||= Dir.pwd 14 | vars = { "PWD" => path } 15 | options = { chdir: path } 16 | 17 | unless File.directory?(path) 18 | FileUtils.mkdir_p(path) 19 | end 20 | 21 | @cmd_output = "" 22 | @cmd_status = 0 23 | Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| 24 | # We are not using stdin so we should close it, in case the command we 25 | # are running waits for input. 26 | stdin.close 27 | @cmd_output << stdout.read 28 | @cmd_output << stderr.read 29 | @cmd_status = wait_thr.value.exitstatus 30 | end 31 | 32 | [@cmd_output, @cmd_status] 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/gitlab/sidekiq_memory_killer.rb: -------------------------------------------------------------------------------- 1 | module Gitlab 2 | class SidekiqMemoryKiller 3 | # Default the RSS limit to 0, meaning the MemoryKiller is disabled 4 | MAX_RSS = (ENV['SIDEKIQ_MEMORY_KILLER_MAX_RSS'] || 0).to_s.to_i 5 | # Give Sidekiq 15 minutes of grace time after exceeding the RSS limit 6 | GRACE_TIME = (ENV['SIDEKIQ_MEMORY_KILLER_GRACE_TIME'] || 15 * 60).to_s.to_i 7 | # Wait 30 seconds for running jobs to finish during graceful shutdown 8 | SHUTDOWN_WAIT = (ENV['SIDEKIQ_MEMORY_KILLER_SHUTDOWN_WAIT'] || 30).to_s.to_i 9 | 10 | # Create a mutex used to ensure there will be only one thread waiting to 11 | # shut Sidekiq down 12 | MUTEX = Mutex.new 13 | 14 | def call(worker, job, queue) 15 | yield 16 | current_rss = get_rss 17 | 18 | return unless MAX_RSS > 0 && current_rss > MAX_RSS 19 | 20 | Thread.new do 21 | # Return if another thread is already waiting to shut Sidekiq down 22 | return unless MUTEX.try_lock 23 | 24 | Sidekiq.logger.warn "current RSS #{current_rss} exceeds maximum RSS "\ 25 | "#{MAX_RSS}" 26 | Sidekiq.logger.warn "spawned thread that will shut down PID "\ 27 | "#{Process.pid} in #{GRACE_TIME} seconds" 28 | sleep(GRACE_TIME) 29 | 30 | Sidekiq.logger.warn "sending SIGUSR1 to PID #{Process.pid}" 31 | Process.kill('SIGUSR1', Process.pid) 32 | 33 | Sidekiq.logger.warn "waiting #{SHUTDOWN_WAIT} seconds before sending "\ 34 | "SIGTERM to PID #{Process.pid}" 35 | sleep(SHUTDOWN_WAIT) 36 | 37 | Sidekiq.logger.warn "sending SIGTERM to PID #{Process.pid}" 38 | Process.kill('SIGTERM', Process.pid) 39 | end 40 | end 41 | 42 | private 43 | 44 | def get_rss 45 | output, status = Gitlab::Popen.popen(%W(ps -o rss= -p #{Process.pid})) 46 | return 0 unless status.zero? 47 | 48 | output.to_i 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sai-lab/shoko/bbe01346c725ee7342956c57f2295ce1e44636d6/lib/tasks/.keep -------------------------------------------------------------------------------- /lib/tasks/ansible.rake: -------------------------------------------------------------------------------- 1 | namespace :ansible do 2 | desc 'Using Ansible' 3 | 4 | task :deploy do 5 | desc 'Deploy using Ansible' 6 | hosts = "#{Rails.root}/playbook/hosts" 7 | playbook = "#{Rails.root}/playbook/deploy.yml" 8 | system "ansible-playbook -i #{hosts} #{playbook}" 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/tasks/sidekiq.rake: -------------------------------------------------------------------------------- 1 | namespace :sidekiq do 2 | desc 'Start sidekiq' 3 | task start: :environment do 4 | system "bundle exec sidekiq -C #{Rails.root.join('config', 'sidekiq.yml')}" 5 | end 6 | 7 | task :sidekiqctl, [:name, :deadline_timeout] => :environment do |t, args| 8 | system "bundle exec sidekiqctl #{args[:name]} #{Rails.root.join('tmp', 'pids', 'sidekiq.pid')} #{args[:deadline_timeout]}" 9 | end 10 | 11 | desc 'Quiet sends USR1 to sidekiq' 12 | task quiet: :environment do 13 | Rake::Task['sidekiq:sidekiqctl'].invoke('quiet') 14 | end 15 | 16 | desc 'Stop sends TERM to sidekiq' 17 | task stop: :environment do 18 | Rake::Task['sidekiq:sidekiqctl'].invoke('stop', '10') 19 | end 20 | 21 | task before: :environment do 22 | RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV) 23 | end 24 | 25 | task start: :before 26 | task sidekiqctl: :before 27 | end 28 | -------------------------------------------------------------------------------- /log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sai-lab/shoko/bbe01346c725ee7342956c57f2295ce1e44636d6/log/.keep -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 404 Not Found | 書庫 5 | 6 | 7 | 8 | 9 | 10 | 28 | 29 | 30 | 37 |
    38 |
    39 |
    40 |

    41 | 42 |

    43 |

    44 | ご指定のページが見つかりません。 45 |

    46 |

    47 | ご指定のページは削除されたか、移動した可能性がございます。 48 |

    49 | 50 | トップに戻る 51 | 52 |
    53 |
    54 |
    55 |
    56 |
    57 | © Shoko 58 |
    59 |
    60 | 61 | 62 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 422 Unprocessable Entity | 書庫 5 | 6 | 7 | 8 | 9 | 10 | 28 | 29 | 30 | 37 |
    38 |
    39 |
    40 |

    41 | 42 |

    43 |

    44 | ページが表示できません。 45 |

    46 |

    47 | ご不便をおかけし申し訳ございません。 48 |
    49 | 正常にご覧いただけるよう、解決に取り組んでおります。 50 |

    51 | 52 | トップに戻る 53 | 54 |
    55 |
    56 |
    57 |
    58 |
    59 | © Shoko 60 |
    61 |
    62 | 63 | 64 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 500 Internal Server Error | 書庫 5 | 6 | 7 | 8 | 9 | 10 | 28 | 29 | 30 | 37 |
    38 |
    39 |
    40 |

    41 | 42 |

    43 |

    44 | ページが表示できません。 45 |

    46 |

    47 | ご不便をおかけし申し訳ございません。 48 |
    49 | 正常にご覧いただけるよう、解決に取り組んでおります。 50 |

    51 | 52 | トップに戻る 53 | 54 |
    55 |
    56 |
    57 |
    58 |
    59 | © Shoko 60 |
    61 |
    62 | 63 | 64 | -------------------------------------------------------------------------------- /public/fonts/logo_type_gothic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sai-lab/shoko/bbe01346c725ee7342956c57f2295ce1e44636d6/public/fonts/logo_type_gothic.eot -------------------------------------------------------------------------------- /public/fonts/logo_type_gothic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sai-lab/shoko/bbe01346c725ee7342956c57f2295ce1e44636d6/public/fonts/logo_type_gothic.ttf -------------------------------------------------------------------------------- /public/fonts/logo_type_gothic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sai-lab/shoko/bbe01346c725ee7342956c57f2295ce1e44636d6/public/fonts/logo_type_gothic.woff -------------------------------------------------------------------------------- /public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sai-lab/shoko/bbe01346c725ee7342956c57f2295ce1e44636d6/public/images/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /spec/controllers/admin/documents_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Admin::DocumentsController, type: :controller do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/admin/pictures_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Admin::PicturesController, type: :controller do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/admin/sidekiq_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Admin::SidekiqController, type: :controller do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/admin/users_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Admin::UsersController, type: :controller do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/admin/web_hooks_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Admin::WebHooksController, type: :controller do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/documents_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe DocumentsController, :type => :controller do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/pictures_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe PicturesController, type: :controller do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/record_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe RecordController, type: :controller do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/templates_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe TemplatesController, :type => :controller do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/top_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe TopController, :type => :controller do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/factories/documents.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: documents 4 | # 5 | # id :integer not null, primary key 6 | # title :string default(""), not null 7 | # markdown :text default(""), not null 8 | # draft_flag :boolean default(FALSE), not null 9 | # created_at :datetime not null 10 | # updated_at :datetime not null 11 | # 12 | 13 | FactoryGirl.define do 14 | factory :document do 15 | 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /spec/factories/pictures.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: pictures 4 | # 5 | # id :integer not null, primary key 6 | # attachment_file_name :string 7 | # attachment_content_type :string 8 | # attachment_file_size :integer 9 | # attachment_updated_at :datetime 10 | # created_at :datetime not null 11 | # updated_at :datetime not null 12 | # 13 | 14 | FactoryGirl.define do 15 | factory :picture do 16 | 17 | end 18 | 19 | end 20 | -------------------------------------------------------------------------------- /spec/factories/templates.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: templates 4 | # 5 | # id :integer not null, primary key 6 | # title :string default(""), not null 7 | # markdown :text default(""), not null 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # name :string default(""), not null 11 | # pattern :string default("") 12 | # 13 | 14 | FactoryGirl.define do 15 | factory :template do 16 | 17 | end 18 | 19 | end 20 | -------------------------------------------------------------------------------- /spec/factories/user_documents.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: user_documents 4 | # 5 | # id :integer not null, primary key 6 | # user_id :integer not null 7 | # document_id :integer not null 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # 11 | 12 | FactoryGirl.define do 13 | factory :user_document do 14 | user nil 15 | document nil 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /spec/factories/users.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: users 4 | # 5 | # id :integer not null, primary key 6 | # account :string default(""), not null 7 | # encrypted_password :string default(""), not null 8 | # name :string default(""), not null 9 | # created_at :datetime 10 | # updated_at :datetime 11 | # admin_flag :boolean default(FALSE), not null 12 | # grade :integer default(1), not null 13 | # email :string default(""), not null 14 | # reset_password_token :string 15 | # reset_password_sent_at :datetime 16 | # 17 | 18 | FactoryGirl.define do 19 | factory :user do 20 | 21 | end 22 | 23 | end 24 | -------------------------------------------------------------------------------- /spec/factories/web_hooks.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: web_hooks 4 | # 5 | # id :integer not null, primary key 6 | # url :string default(""), not null 7 | # created_at :datetime not null 8 | # updated_at :datetime not null 9 | # name :string default(""), not null 10 | # 11 | 12 | FactoryGirl.define do 13 | factory :web_hook do 14 | 15 | end 16 | 17 | end 18 | -------------------------------------------------------------------------------- /spec/jobs/file_job_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe FileJob, type: :job do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/jobs/web_hook_job_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe WebHookJob, type: :job do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/document_spec.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: documents 4 | # 5 | # id :integer not null, primary key 6 | # title :string default(""), not null 7 | # markdown :text default(""), not null 8 | # draft_flag :boolean default(FALSE), not null 9 | # created_at :datetime not null 10 | # updated_at :datetime not null 11 | # 12 | 13 | require 'rails_helper' 14 | 15 | RSpec.describe Document, :type => :model do 16 | end 17 | -------------------------------------------------------------------------------- /spec/models/picture_spec.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: pictures 4 | # 5 | # id :integer not null, primary key 6 | # attachment_file_name :string 7 | # attachment_content_type :string 8 | # attachment_file_size :integer 9 | # attachment_updated_at :datetime 10 | # created_at :datetime not null 11 | # updated_at :datetime not null 12 | # 13 | 14 | require 'rails_helper' 15 | 16 | RSpec.describe Picture, type: :model do 17 | pending "add some examples to (or delete) #{__FILE__}" 18 | end 19 | -------------------------------------------------------------------------------- /spec/models/template_spec.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: templates 4 | # 5 | # id :integer not null, primary key 6 | # title :string default(""), not null 7 | # markdown :text default(""), not null 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # name :string default(""), not null 11 | # pattern :string default("") 12 | # 13 | 14 | require 'rails_helper' 15 | 16 | RSpec.describe Template, :type => :model do 17 | pending "add some examples to (or delete) #{__FILE__}" 18 | end 19 | -------------------------------------------------------------------------------- /spec/models/user_document_spec.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: user_documents 4 | # 5 | # id :integer not null, primary key 6 | # user_id :integer not null 7 | # document_id :integer not null 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # 11 | 12 | require 'rails_helper' 13 | 14 | RSpec.describe UserDocument, :type => :model do 15 | end 16 | -------------------------------------------------------------------------------- /spec/models/user_spec.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: users 4 | # 5 | # id :integer not null, primary key 6 | # account :string default(""), not null 7 | # encrypted_password :string default(""), not null 8 | # name :string default(""), not null 9 | # created_at :datetime 10 | # updated_at :datetime 11 | # admin_flag :boolean default(FALSE), not null 12 | # grade :integer default(1), not null 13 | # email :string default(""), not null 14 | # reset_password_token :string 15 | # reset_password_sent_at :datetime 16 | # 17 | 18 | require 'rails_helper' 19 | 20 | RSpec.describe User, :type => :model do 21 | end 22 | -------------------------------------------------------------------------------- /spec/models/web_hook_spec.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: web_hooks 4 | # 5 | # id :integer not null, primary key 6 | # url :string default(""), not null 7 | # created_at :datetime not null 8 | # updated_at :datetime not null 9 | # name :string default(""), not null 10 | # 11 | 12 | require 'rails_helper' 13 | 14 | RSpec.describe WebHook, type: :model do 15 | pending "add some examples to (or delete) #{__FILE__}" 16 | end 17 | -------------------------------------------------------------------------------- /spec/rails_helper.rb: -------------------------------------------------------------------------------- 1 | # This file is copied to spec/ when you run 'rails generate rspec:install' 2 | ENV["RAILS_ENV"] ||= 'test' 3 | require 'spec_helper' 4 | require File.expand_path("../../config/environment", __FILE__) 5 | require 'rspec/rails' 6 | # Add additional requires below this line. Rails is not loaded until this point! 7 | 8 | # Requires supporting ruby files with custom matchers and macros, etc, in 9 | # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are 10 | # run as spec files by default. This means that files in spec/support that end 11 | # in _spec.rb will both be required and run as specs, causing the specs to be 12 | # run twice. It is recommended that you do not name files matching this glob to 13 | # end with _spec.rb. You can configure this pattern with the --pattern 14 | # option on the command line or in ~/.rspec, .rspec or `.rspec-local`. 15 | # 16 | # The following line is provided for convenience purposes. It has the downside 17 | # of increasing the boot-up time by auto-requiring all files in the support 18 | # directory. Alternatively, in the individual `*_spec.rb` files, manually 19 | # require only the support files necessary. 20 | # 21 | # Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } 22 | 23 | # Checks for pending migrations before tests are run. 24 | # If you are not using ActiveRecord, you can remove this line. 25 | ActiveRecord::Migration.maintain_test_schema! 26 | 27 | RSpec.configure do |config| 28 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 29 | config.fixture_path = "#{::Rails.root}/spec/fixtures" 30 | 31 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 32 | # examples within a transaction, remove the following line or assign false 33 | # instead of true. 34 | config.use_transactional_fixtures = true 35 | 36 | # RSpec Rails can automatically mix in different behaviours to your tests 37 | # based on their file location, for example enabling you to call `get` and 38 | # `post` in specs under `spec/controllers`. 39 | # 40 | # You can disable this behaviour by removing the line below, and instead 41 | # explicitly tag your specs with their type, e.g.: 42 | # 43 | # RSpec.describe UsersController, :type => :controller do 44 | # # ... 45 | # end 46 | # 47 | # The different available types are documented in the features, such as in 48 | # https://relishapp.com/rspec/rspec-rails/docs 49 | config.infer_spec_type_from_file_location! 50 | end 51 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sai-lab/shoko/bbe01346c725ee7342956c57f2295ce1e44636d6/vendor/assets/javascripts/.keep -------------------------------------------------------------------------------- /vendor/assets/javascripts/codemirror/addon/mode/overlay.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | // Utility function that allows modes to be combined. The mode given 5 | // as the base argument takes care of most of the normal mode 6 | // functionality, but a second (typically simple) mode is used, which 7 | // can override the style of text. Both modes get to parse all of the 8 | // text, but when both assign a non-null style to a piece of code, the 9 | // overlay wins, unless the combine argument was true and not overridden, 10 | // or state.overlay.combineTokens was true, in which case the styles are 11 | // combined. 12 | 13 | (function(mod) { 14 | if (typeof exports == "object" && typeof module == "object") // CommonJS 15 | mod(require("../../lib/codemirror")); 16 | else if (typeof define == "function" && define.amd) // AMD 17 | define(["../../lib/codemirror"], mod); 18 | else // Plain browser env 19 | mod(CodeMirror); 20 | })(function(CodeMirror) { 21 | "use strict"; 22 | 23 | CodeMirror.overlayMode = function(base, overlay, combine) { 24 | return { 25 | startState: function() { 26 | return { 27 | base: CodeMirror.startState(base), 28 | overlay: CodeMirror.startState(overlay), 29 | basePos: 0, baseCur: null, 30 | overlayPos: 0, overlayCur: null, 31 | streamSeen: null 32 | }; 33 | }, 34 | copyState: function(state) { 35 | return { 36 | base: CodeMirror.copyState(base, state.base), 37 | overlay: CodeMirror.copyState(overlay, state.overlay), 38 | basePos: state.basePos, baseCur: null, 39 | overlayPos: state.overlayPos, overlayCur: null 40 | }; 41 | }, 42 | 43 | token: function(stream, state) { 44 | if (stream != state.streamSeen || 45 | Math.min(state.basePos, state.overlayPos) < stream.start) { 46 | state.streamSeen = stream; 47 | state.basePos = state.overlayPos = stream.start; 48 | } 49 | 50 | if (stream.start == state.basePos) { 51 | state.baseCur = base.token(stream, state.base); 52 | state.basePos = stream.pos; 53 | } 54 | if (stream.start == state.overlayPos) { 55 | stream.pos = stream.start; 56 | state.overlayCur = overlay.token(stream, state.overlay); 57 | state.overlayPos = stream.pos; 58 | } 59 | stream.pos = Math.min(state.basePos, state.overlayPos); 60 | 61 | // state.overlay.combineTokens always takes precedence over combine, 62 | // unless set to null 63 | if (state.overlayCur == null) return state.baseCur; 64 | else if (state.baseCur != null && 65 | state.overlay.combineTokens || 66 | combine && state.overlay.combineTokens == null) 67 | return state.baseCur + " " + state.overlayCur; 68 | else return state.overlayCur; 69 | }, 70 | 71 | indent: base.indent && function(state, textAfter) { 72 | return base.indent(state.base, textAfter); 73 | }, 74 | electricChars: base.electricChars, 75 | 76 | innerMode: function(state) { return {state: state.base, mode: base}; }, 77 | 78 | blankLine: function(state) { 79 | if (base.blankLine) base.blankLine(state.base); 80 | if (overlay.blankLine) overlay.blankLine(state.overlay); 81 | } 82 | }; 83 | }; 84 | 85 | }); 86 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/components/accordion.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(t){var i;window.UIkit&&(i=t(UIkit)),"function"==typeof define&&define.amd&&define("uikit-accordion",["uikit"],function(){return i||t(UIkit)})}(function(t){"use strict";function i(i){var o=t.$(i),e="auto";if(o.is(":visible"))e=o.outerHeight();else{var a={position:o.css("position"),visibility:o.css("visibility"),display:o.css("display")};e=o.css({position:"absolute",visibility:"hidden",display:"block"}).outerHeight(),o.css(a)}return e}return t.component("accordion",{defaults:{showfirst:!0,collapse:!0,animate:!0,easing:"swing",duration:300,toggle:".uk-accordion-title",containers:".uk-accordion-content",clsactive:"uk-active"},boot:function(){t.ready(function(i){setTimeout(function(){t.$("[data-uk-accordion]",i).each(function(){var i=t.$(this);i.data("accordion")||t.accordion(i,t.Utils.options(i.attr("data-uk-accordion")))})},0)})},init:function(){var i=this;this.element.on("click.uikit.accordion",this.options.toggle,function(o){o.preventDefault(),i.toggleItem(t.$(this).data("wrapper"),i.options.animate,i.options.collapse)}),this.update(),this.options.showfirst&&this.toggleItem(this.toggle.eq(0).data("wrapper"),!1,!1)},toggleItem:function(o,e,a){var n=this;o.data("toggle").toggleClass(this.options.clsactive);var s=o.data("toggle").hasClass(this.options.clsactive);a&&(this.toggle.not(o.data("toggle")).removeClass(this.options.clsactive),this.content.not(o.data("content")).parent().stop().css("overflow","hidden").animate({height:0},{easing:this.options.easing,duration:e?this.options.duration:0}).attr("aria-expanded","false")),o.stop().css("overflow","hidden"),e?o.animate({height:s?i(o.data("content")):0},{easing:this.options.easing,duration:this.options.duration,complete:function(){s&&(o.css({overflow:"",height:"auto"}),t.Utils.checkDisplay(o.data("content"))),n.trigger("display.uk.check")}}):(o.height(s?"auto":0),s&&(o.css({overflow:""}),t.Utils.checkDisplay(o.data("content"))),this.trigger("display.uk.check")),o.attr("aria-expanded",s),this.element.trigger("toggle.uk.accordion",[s,o.data("toggle"),o.data("content")])},update:function(){var i,o,e,a=this;this.toggle=this.find(this.options.toggle),this.content=this.find(this.options.containers),this.content.each(function(n){i=t.$(this),i.parent().data("wrapper")?o=i.parent():(o=t.$(this).wrap('
    ').parent(),o.attr("aria-expanded","false")),e=a.toggle.eq(n),o.data("toggle",e),o.data("content",i),e.data("wrapper",o),i.data("wrapper",o)}),this.element.trigger("update.uk.accordion",[this])}}),t.accordion}); -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/components/form-password.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(t){var i;window.UIkit&&(i=t(UIkit)),"function"==typeof define&&define.amd&&define("uikit-form-password",["uikit"],function(){return i||t(UIkit)})}(function(t){"use strict";return t.component("formPassword",{defaults:{lblShow:"Show",lblHide:"Hide"},boot:function(){t.$html.on("click.formpassword.uikit","[data-uk-form-password]",function(i){var e=t.$(this);e.data("formPassword")||(i.preventDefault(),t.formPassword(e,t.Utils.options(e.attr("data-uk-form-password"))),e.trigger("click"))})},init:function(){var t=this;this.on("click",function(i){if(i.preventDefault(),t.input.length){var e=t.input.attr("type");t.input.attr("type","text"==e?"password":"text"),t.element.html(t.options["text"==e?"lblShow":"lblHide"])}}),this.input=this.element.next("input").length?this.element.next("input"):this.element.prev("input"),this.element.html(this.options[this.input.is("[type='password']")?"lblShow":"lblHide"]),this.element.data("formPassword",this)}}),t.formPassword}); -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/components/form-select.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(t){var e;window.UIkit&&(e=t(UIkit)),"function"==typeof define&&define.amd&&define("uikit-form-select",["uikit"],function(){return e||t(UIkit)})}(function(t){"use strict";return t.component("formSelect",{defaults:{target:">span:first",activeClass:"uk-active"},boot:function(){t.ready(function(e){t.$("[data-uk-form-select]",e).each(function(){var e=t.$(this);e.data("formSelect")||t.formSelect(e,t.Utils.options(e.attr("data-uk-form-select")))})})},init:function(){var t=this;this.target=this.find(this.options.target),this.select=this.find("select"),this.select.on("change",function(){var e=t.select[0],i=function(){try{t.target.text(e.options[e.selectedIndex].text)}catch(n){}return t.element[t.select.val()?"addClass":"removeClass"](t.options.activeClass),i};return i()}()),this.element.data("formSelect",this)}}),t.formSelect}); -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/components/notify.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(t){var e;window.UIkit&&(e=t(UIkit)),"function"==typeof define&&define.amd&&define("uikit-notify",["uikit"],function(){return e||t(UIkit)})}(function(t){"use strict";var e={},i={},s=function(e){return"string"==t.$.type(e)&&(e={message:e}),arguments[1]&&(e=t.$.extend(e,"string"==t.$.type(arguments[1])?{status:arguments[1]}:arguments[1])),new n(e).show()},o=function(t,e){var s;if(t)for(s in i)t===i[s].group&&i[s].close(e);else for(s in i)i[s].close(e)},n=function(s){this.options=t.$.extend({},n.defaults,s),this.uuid=t.Utils.uid("notifymsg"),this.element=t.$(['
    ','',"
    ","
    "].join("")).data("notifyMessage",this),this.content(this.options.message),this.options.status&&(this.element.addClass("uk-notify-message-"+this.options.status),this.currentstatus=this.options.status),this.group=this.options.group,i[this.uuid]=this,e[this.options.pos]||(e[this.options.pos]=t.$('
    ').appendTo("body").on("click",".uk-notify-message",function(){var e=t.$(this).data("notifyMessage");e.element.trigger("manualclose.uk.notify",[e]),e.close()}))};return t.$.extend(n.prototype,{uuid:!1,element:!1,timout:!1,currentstatus:"",group:!1,show:function(){if(!this.element.is(":visible")){var t=this;e[this.options.pos].show().prepend(this.element);var i=parseInt(this.element.css("margin-bottom"),10);return this.element.css({opacity:0,"margin-top":-1*this.element.outerHeight(),"margin-bottom":0}).animate({opacity:1,"margin-top":0,"margin-bottom":i},function(){if(t.options.timeout){var e=function(){t.close()};t.timeout=setTimeout(e,t.options.timeout),t.element.hover(function(){clearTimeout(t.timeout)},function(){t.timeout=setTimeout(e,t.options.timeout)})}}),this}},close:function(t){var s=this,o=function(){s.element.remove(),e[s.options.pos].children().length||e[s.options.pos].hide(),s.options.onClose.apply(s,[]),s.element.trigger("close.uk.notify",[s]),delete i[s.uuid]};this.timeout&&clearTimeout(this.timeout),t?o():this.element.animate({opacity:0,"margin-top":-1*this.element.outerHeight(),"margin-bottom":0},function(){o()})},content:function(t){var e=this.element.find(">div");return t?(e.html(t),this):e.html()},status:function(t){return t?(this.element.removeClass("uk-notify-message-"+this.currentstatus).addClass("uk-notify-message-"+t),this.currentstatus=t,this):this.currentstatus}}),n.defaults={message:"",status:"",timeout:5e3,group:null,pos:"top-center",onClose:function(){}},t.notify=s,t.notify.message=n,t.notify.closeAll=o,s}); -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/components/pagination.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(t){var e;window.UIkit&&(e=t(UIkit)),"function"==typeof define&&define.amd&&define("uikit-pagination",["uikit"],function(){return e||t(UIkit)})}(function(t){"use strict";return t.component("pagination",{defaults:{items:1,itemsOnPage:1,pages:0,displayedPages:7,edges:1,currentPage:0,lblPrev:!1,lblNext:!1,onSelectPage:function(){}},boot:function(){t.ready(function(e){t.$("[data-uk-pagination]",e).each(function(){var e=t.$(this);e.data("pagination")||t.pagination(e,t.Utils.options(e.attr("data-uk-pagination")))})})},init:function(){var e=this;this.pages=this.options.pages?this.options.pages:Math.ceil(this.options.items/this.options.itemsOnPage)?Math.ceil(this.options.items/this.options.itemsOnPage):1,this.currentPage=this.options.currentPage,this.halfDisplayed=this.options.displayedPages/2,this.on("click","a[data-page]",function(i){i.preventDefault(),e.selectPage(t.$(this).data("page"))}),this._render()},_getInterval:function(){return{start:Math.ceil(this.currentPage>this.halfDisplayed?Math.max(Math.min(this.currentPage-this.halfDisplayed,this.pages-this.options.displayedPages),0):0),end:Math.ceil(this.currentPage>this.halfDisplayed?Math.min(this.currentPage+this.halfDisplayed,this.pages):Math.min(this.options.displayedPages,this.pages))}},render:function(t){this.pages=t?t:this.pages,this._render()},selectPage:function(t,e){this.currentPage=t,this.render(e),this.options.onSelectPage.apply(this,[t]),this.trigger("select.uk.pagination",[t,this])},_render:function(){var t,e=this.options,i=this._getInterval();if(this.element.empty(),e.lblPrev&&this._append(e.currentPage-1,{text:e.lblPrev}),i.start>0&&e.edges>0){var s=Math.min(e.edges,i.start);for(t=0;s>t;t++)this._append(t);e.edges..."):i.start-e.edges==1&&this._append(e.edges)}for(t=i.start;t0){this.pages-e.edges>i.end&&this.pages-e.edges-i.end!=1?this.element.append("
  • ...
  • "):this.pages-e.edges-i.end==1&&this._append(i.end++);var a=Math.max(this.pages-e.edges,i.end);for(t=a;te?0:e'+a.text+"":'
  • '+a.text+"
  • ",this.element.append(s)}}),t.pagination}); -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/components/search.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(e){var s;window.UIkit&&(s=e(UIkit)),"function"==typeof define&&define.amd&&define("uikit-search",["uikit"],function(){return s||e(UIkit)})}(function(e){"use strict";e.component("search",{defaults:{msgResultsHeader:"Search Results",msgMoreResults:"More Results",msgNoResults:"No results found",template:'',renderer:function(e){var s=this.options;this.dropdown.append(this.template({items:e.results||[],msgResultsHeader:s.msgResultsHeader,msgMoreResults:s.msgMoreResults,msgNoResults:s.msgNoResults})),this.show()}},boot:function(){e.$html.on("focus.search.uikit","[data-uk-search]",function(){var s=e.$(this);s.data("search")||e.search(s,e.Utils.options(s.attr("data-uk-search")))})},init:function(){var s=this;this.autocomplete=e.autocomplete(this.element,this.options),this.autocomplete.dropdown.addClass("uk-dropdown-search"),this.autocomplete.input.on("keyup",function(){s.element[s.autocomplete.input.val()?"addClass":"removeClass"]("uk-active")}).closest("form").on("reset",function(){s.value="",s.element.removeClass("uk-active")}),this.on("selectitem.uk.autocomplete",function(e,t){t.url?location.href=t.url:t.moreresults&&s.autocomplete.input.closest("form").submit()}),this.element.data("search",this)}})}); -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/components/timepicker.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(t){var e;window.UIkit&&(e=t(UIkit)),"function"==typeof define&&define.amd&&define("uikit-search",["uikit"],function(){return e||t(UIkit)})}(function(t){"use strict";function e(t,e){t=t||0,e=e||24;var i,o,a={"12h":[],"24h":[]};for(i=t,o="";e>i;i++)o=""+i,10>i&&(o="0"+o),a["24h"].push({value:o+":00"}),a["24h"].push({value:o+":30"}),0===i&&(o=12,a["12h"].push({value:o+":00 AM"}),a["12h"].push({value:o+":30 AM"})),i>0&&13>i&&12!==i&&(a["12h"].push({value:o+":00 AM"}),a["12h"].push({value:o+":30 AM"})),i>=12&&(o-=12,0===o&&(o=12),10>o&&(o="0"+String(o)),a["12h"].push({value:o+":00 PM"}),a["12h"].push({value:o+":30 PM"}));return a}t.component("timepicker",{defaults:{format:"24h",delay:0,start:0,end:24},boot:function(){t.$html.on("focus.timepicker.uikit","[data-uk-timepicker]",function(){var e=t.$(this);if(!e.data("timepicker")){var i=t.timepicker(e,t.Utils.options(e.attr("data-uk-timepicker")));setTimeout(function(){i.autocomplete.input.focus()},40)}})},init:function(){var i,o=this,a=e(this.options.start,this.options.end);this.options.minLength=0,this.options.template='',this.options.source=function(t){t(a[o.options.format]||a["12h"])},this.element.is("input")?(this.element.wrap('
    '),i=this.element.parent()):i=this.element.addClass("uk-autocomplete"),this.autocomplete=t.autocomplete(i,this.options),this.autocomplete.dropdown.addClass("uk-dropdown-small uk-dropdown-scrollable"),this.autocomplete.on("show.uk.autocomplete",function(){var t=o.autocomplete.dropdown.find('[data-value="'+o.autocomplete.input.val()+'"]');setTimeout(function(){o.autocomplete.pick(t,!0)},10)}),this.autocomplete.input.on("focus",function(){o.autocomplete.value=Math.random(),o.autocomplete.triggercomplete()}).on("blur",t.Utils.debounce(function(){o.checkTime()},100)),this.element.data("timepicker",this)},checkTime:function(){var t,e,i,o,a="AM",u=this.autocomplete.input.val();"12h"==this.options.format?(t=u.split(" "),e=t[0].split(":"),a=t[1]):e=u.split(":"),i=parseInt(e[0],10),o=parseInt(e[1],10),isNaN(i)&&(i=0),isNaN(o)&&(o=0),"12h"==this.options.format?(i>12?i=12:0>i&&(i=12),"am"===a||"a"===a?a="AM":("pm"===a||"p"===a)&&(a="PM"),"AM"!==a&&"PM"!==a&&(a="AM")):i>=24?i=23:0>i&&(i=0),0>o?o=0:o>=60&&(o=0),this.autocomplete.input.val(this.formatTime(i,o,a)).trigger("change")},formatTime:function(t,e,i){return t=10>t?"0"+t:t,e=10>e?"0"+e:e,t+":"+e+("12h"==this.options.format?" "+i:"")}})}); -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/components/upload.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(e){var t;window.UIkit&&(t=e(UIkit)),"function"==typeof define&&define.amd&&define("uikit-upload",["uikit"],function(){return t||e(UIkit)})}(function(e){"use strict";function t(o,a){function r(t,n){var o=new FormData,a=new XMLHttpRequest;if(n.before(n,t)!==!1){for(var r,i=0;r=t[i];i++)o.append(n.param,r);for(var l in n.params)o.append(l,n.params[l]);a.upload.addEventListener("progress",function(e){var t=e.loaded/e.total*100;n.progress(t,e)},!1),a.addEventListener("loadstart",function(e){n.loadstart(e)},!1),a.addEventListener("load",function(e){n.load(e)},!1),a.addEventListener("loadend",function(e){n.loadend(e)},!1),a.addEventListener("error",function(e){n.error(e)},!1),a.addEventListener("abort",function(e){n.abort(e)},!1),a.open(n.method,n.action,!0),"json"==n.type&&a.setRequestHeader("Accept","application/json"),a.onreadystatechange=function(){if(n.readystatechange(a),4==a.readyState){var t=a.responseText;if("json"==n.type)try{t=e.$.parseJSON(t)}catch(o){t=!1}n.complete(t,a)}},n.beforeSend(a),a.send(o)}}if(!e.support.ajaxupload)return this;if(a=e.$.extend({},t.defaults,a),o.length){if("*.*"!==a.allow)for(var i,l=0;i=o[l];l++)if(!n(a.allow,i.name))return"string"==typeof a.notallowed?alert(a.notallowed):a.notallowed(i,a),void 0;var s=a.complete;if(a.single){var d=o.length,f=0,p=!0;a.beforeAll(o),a.complete=function(e,t){f+=1,s(e,t),a.filelimit&&f>=a.filelimit&&(p=!1),p&&d>f?r([o[f]],a):a.allcomplete(e,t)},r([o[0]],a)}else a.complete=function(e,t){s(e,t),a.allcomplete(e,t)},r(o,a)}}function n(e,t){var n="^"+e.replace(/\//g,"\\/").replace(/\*\*/g,"(\\/[^\\/]+)*").replace(/\*/g,"[^\\/]+").replace(/((?!\\))\?/g,"$1.")+"$";return n="^"+n+"$",null!==t.match(new RegExp(n,"i"))}return e.component("uploadSelect",{init:function(){var e=this;this.on("change",function(){t(e.element[0].files,e.options);var n=e.element.clone(!0).data("uploadSelect",e);e.element.replaceWith(n),e.element=n})}}),e.component("uploadDrop",{defaults:{dragoverClass:"uk-dragover"},init:function(){var e=this,n=!1;this.on("drop",function(n){n.dataTransfer&&n.dataTransfer.files&&(n.stopPropagation(),n.preventDefault(),e.element.removeClass(e.options.dragoverClass),e.element.trigger("dropped.uk.upload",[n.dataTransfer.files]),t(n.dataTransfer.files,e.options))}).on("dragenter",function(e){e.stopPropagation(),e.preventDefault()}).on("dragover",function(t){t.stopPropagation(),t.preventDefault(),n||(e.element.addClass(e.options.dragoverClass),n=!0)}).on("dragleave",function(t){t.stopPropagation(),t.preventDefault(),e.element.removeClass(e.options.dragoverClass),n=!1})}}),e.support.ajaxupload=function(){function e(){var e=document.createElement("INPUT");return e.type="file","files"in e}function t(){var e=new XMLHttpRequest;return!!(e&&"upload"in e&&"onprogress"in e.upload)}function n(){return!!window.FormData}return e()&&t()&&n()}(),e.support.ajaxupload&&e.$.event.props.push("dataTransfer"),t.defaults={action:"",single:!0,method:"POST",param:"files[]",params:{},allow:"*.*",type:"text",filelimit:!1,before:function(){},beforeSend:function(){},beforeAll:function(){},loadstart:function(){},load:function(){},loadend:function(){},error:function(){},abort:function(){},progress:function(){},complete:function(){},allcomplete:function(){},readystatechange:function(){},notallowed:function(e,t){alert("Only the following file types are allowed: "+t.allow)}},e.Utils.xhrupload=t,t}); -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/core/alert.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(t){"use strict";t.component("alert",{defaults:{fade:!0,duration:200,trigger:".uk-alert-close"},boot:function(){t.$html.on("click.alert.uikit","[data-uk-alert]",function(i){var o=t.$(this);if(!o.data("alert")){var e=t.alert(o,t.Utils.options(o.attr("data-uk-alert")));t.$(i.target).is(e.options.trigger)&&(i.preventDefault(),e.close())}})},init:function(){var t=this;this.on("click",this.options.trigger,function(i){i.preventDefault(),t.close()})},close:function(){var t=this.trigger("close.uk.alert"),i=function(){this.trigger("closed.uk.alert").remove()}.bind(this);this.options.fade?t.css("overflow","hidden").css("max-height",t.height()).animate({height:0,opacity:0,"padding-top":0,"padding-bottom":0,"margin-top":0,"margin-bottom":0},this.options.duration,i):i()}})}(UIkit); -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/core/button.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(t){"use strict";t.component("buttonRadio",{defaults:{activeClass:"uk-active",target:".uk-button"},boot:function(){t.$html.on("click.buttonradio.uikit","[data-uk-button-radio]",function(i){var a=t.$(this);if(!a.data("buttonRadio")){var e=t.buttonRadio(a,t.Utils.options(a.attr("data-uk-button-radio"))),o=t.$(i.target);o.is(e.options.target)&&o.trigger("click")}})},init:function(){var i=this;this.find(i.options.target).attr("aria-checked","false").filter("."+i.options.activeClass).attr("aria-checked","true"),this.on("click",this.options.target,function(a){var e=t.$(this);e.is('a[href="#"]')&&a.preventDefault(),i.find(i.options.target).not(e).removeClass(i.options.activeClass).blur(),e.addClass(i.options.activeClass),i.find(i.options.target).not(e).attr("aria-checked","false"),e.attr("aria-checked","true"),i.trigger("change.uk.button",[e])})},getSelected:function(){return this.find("."+this.options.activeClass)}}),t.component("buttonCheckbox",{defaults:{activeClass:"uk-active",target:".uk-button"},boot:function(){t.$html.on("click.buttoncheckbox.uikit","[data-uk-button-checkbox]",function(i){var a=t.$(this);if(!a.data("buttonCheckbox")){var e=t.buttonCheckbox(a,t.Utils.options(a.attr("data-uk-button-checkbox"))),o=t.$(i.target);o.is(e.options.target)&&o.trigger("click")}})},init:function(){var i=this;this.find(i.options.target).attr("aria-checked","false").filter("."+i.options.activeClass).attr("aria-checked","true"),this.on("click",this.options.target,function(a){var e=t.$(this);e.is('a[href="#"]')&&a.preventDefault(),e.toggleClass(i.options.activeClass).blur(),e.attr("aria-checked",e.hasClass(i.options.activeClass)),i.trigger("change.uk.button",[e])})},getSelected:function(){return this.find("."+this.options.activeClass)}}),t.component("button",{defaults:{},boot:function(){t.$html.on("click.button.uikit","[data-uk-button]",function(){var i=t.$(this);if(!i.data("button")){{t.button(i,t.Utils.options(i.attr("data-uk-button")))}i.trigger("click")}})},init:function(){var t=this;this.element.attr("aria-pressed",this.element.hasClass("uk-active")),this.on("click",function(i){t.element.is('a[href="#"]')&&i.preventDefault(),t.toggle(),t.trigger("change.uk.button",[t.element.blur().hasClass("uk-active")])})},toggle:function(){this.element.toggleClass("uk-active"),this.element.attr("aria-pressed",this.element.hasClass("uk-active"))}})}(UIkit); -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/core/cover.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(t){"use strict";t.component("cover",{defaults:{automute:!0},boot:function(){t.ready(function(i){t.$("[data-uk-cover]",i).each(function(){var i=t.$(this);if(!i.data("cover")){t.cover(i,t.Utils.options(i.attr("data-uk-cover")))}})})},init:function(){if(this.parent=this.element.parent(),t.$win.on("load resize orientationchange",t.Utils.debounce(function(){this.check()}.bind(this),100)),this.on("display.uk.check",function(){this.element.is(":visible")&&this.check()}.bind(this)),this.check(),this.element.is("iframe")&&this.options.automute){var i=this.element.attr("src");this.element.attr("src","").on("load",function(){this.contentWindow.postMessage('{ "event": "command", "func": "mute", "method":"setVolume", "value":0}',"*")}).attr("src",[i,i.indexOf("?")>-1?"&":"?","enablejsapi=1&api=1"].join(""))}},check:function(){this.element.css({width:"",height:""}),this.dimension={w:this.element.width(),h:this.element.height()},this.element.attr("width")&&!isNaN(this.element.attr("width"))&&(this.dimension.w=this.element.attr("width")),this.element.attr("height")&&!isNaN(this.element.attr("height"))&&(this.dimension.h=this.element.attr("height")),this.ratio=this.dimension.w/this.dimension.h;var t,i,e=this.parent.width(),n=this.parent.height();e/this.ratio=100;return n&&!this.options.ignorestacked?this.revert():t.Utils.matchHeights(this.elements,this.options),this}},revert:function(){return this.elements.css("min-height",""),this}}),t.component("gridMargin",{defaults:{cls:"uk-grid-margin"},boot:function(){t.ready(function(i){t.$("[data-uk-grid-margin]",i).each(function(){var i,n=t.$(this);n.data("gridMargin")||(i=t.gridMargin(n,t.Utils.options(n.attr("data-uk-grid-margin"))))})})},init:function(){t.stackMargin(this.element,this.options)}})}(UIkit); -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/core/nav.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(i){"use strict";function t(t){var s=i.$(t),a="auto";if(s.is(":visible"))a=s.outerHeight();else{var e={position:s.css("position"),visibility:s.css("visibility"),display:s.css("display")};a=s.css({position:"absolute",visibility:"hidden",display:"block"}).outerHeight(),s.css(e)}return a}i.component("nav",{defaults:{toggle:">li.uk-parent > a[href='#']",lists:">li.uk-parent > ul",multiple:!1},boot:function(){i.ready(function(t){i.$("[data-uk-nav]",t).each(function(){var t=i.$(this);if(!t.data("nav")){i.nav(t,i.Utils.options(t.attr("data-uk-nav")))}})})},init:function(){var t=this;this.on("click.uikit.nav",this.options.toggle,function(s){s.preventDefault();var a=i.$(this);t.open(a.parent()[0]==t.element[0]?a:a.parent("li"))}),this.find(this.options.lists).each(function(){var s=i.$(this),a=s.parent(),e=a.hasClass("uk-active");s.wrap('
    '),a.data("list-container",s.parent()[e?"removeClass":"addClass"]("uk-hidden")),a.attr("aria-expanded",a.hasClass("uk-open")),e&&t.open(a,!0)})},open:function(s,a){var e=this,n=this.element,o=i.$(s),l=o.data("list-container");this.options.multiple||n.children(".uk-open").not(s).each(function(){var t=i.$(this);t.data("list-container")&&t.data("list-container").stop().animate({height:0},function(){i.$(this).parent().removeClass("uk-open").end().addClass("uk-hidden")})}),o.toggleClass("uk-open"),o.attr("aria-expanded",o.hasClass("uk-open")),l&&(o.hasClass("uk-open")&&l.removeClass("uk-hidden"),a?(l.stop().height(o.hasClass("uk-open")?"auto":0),o.hasClass("uk-open")||l.addClass("uk-hidden"),this.trigger("display.uk.check")):l.stop().animate({height:o.hasClass("uk-open")?t(l.find("ul:first")):0},function(){o.hasClass("uk-open")?l.css("height",""):l.addClass("uk-hidden"),e.trigger("display.uk.check")}))}})}(UIkit); -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/core/offcanvas.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(a){"use strict";var t={x:window.scrollX,y:window.scrollY},n=(a.$win,a.$doc,a.$html),i={show:function(i){if(i=a.$(i),i.length){var o=a.$("body"),s=i.find(".uk-offcanvas-bar:first"),e="right"==a.langdirection,f=s.hasClass("uk-offcanvas-bar-flip")?-1:1,r=f*(e?-1:1),c=window.innerWidth-o.width();t={x:window.pageXOffset,y:window.pageYOffset},i.addClass("uk-active"),o.css({width:window.innerWidth-c,height:window.innerHeight}).addClass("uk-offcanvas-page"),o.css(e?"margin-right":"margin-left",(e?-1:1)*s.outerWidth()*r).width(),n.css("margin-top",-1*t.y),s.addClass("uk-offcanvas-bar-show"),this._initElement(i),s.trigger("show.uk.offcanvas",[i,s]),i.attr("aria-hidden","false")}},hide:function(i){var o=a.$("body"),s=a.$(".uk-offcanvas.uk-active"),e="right"==a.langdirection,f=s.find(".uk-offcanvas-bar:first"),r=function(){o.removeClass("uk-offcanvas-page").css({width:"",height:"","margin-left":"","margin-right":""}),s.removeClass("uk-active"),f.removeClass("uk-offcanvas-bar-show"),n.css("margin-top",""),window.scrollTo(t.x,t.y),f.trigger("hide.uk.offcanvas",[s,f]),s.attr("aria-hidden","true")};s.length&&(a.support.transition&&!i?(o.one(a.support.transition.end,function(){r()}).css(e?"margin-right":"margin-left",""),setTimeout(function(){f.removeClass("uk-offcanvas-bar-show")},0)):r())},_initElement:function(t){t.data("OffcanvasInit")||(t.on("click.uk.offcanvas swipeRight.uk.offcanvas swipeLeft.uk.offcanvas",function(t){var n=a.$(t.target);if(!t.type.match(/swipe/)&&!n.hasClass("uk-offcanvas-close")){if(n.hasClass("uk-offcanvas-bar"))return;if(n.parents(".uk-offcanvas-bar:first").length)return}t.stopImmediatePropagation(),i.hide()}),t.on("click","a[href^='#']",function(){var t=a.$(this),n=t.attr("href");"#"!=n&&(a.$doc.one("hide.uk.offcanvas",function(){var i;try{i=a.$(n)}catch(o){i=""}i.length||(i=a.$('[name="'+n.replace("#","")+'"]')),i.length&&t.attr("data-uk-smooth-scroll")&&a.Utils.scrollToElement?a.Utils.scrollToElement(i,a.Utils.options(t.attr("data-uk-smooth-scroll")||"{}")):window.location.href=n}),i.hide())}),t.data("OffcanvasInit",!0))}};a.component("offcanvasTrigger",{boot:function(){n.on("click.offcanvas.uikit","[data-uk-offcanvas]",function(t){t.preventDefault();var n=a.$(this);if(!n.data("offcanvasTrigger")){{a.offcanvasTrigger(n,a.Utils.options(n.attr("data-uk-offcanvas")))}n.trigger("click")}}),n.on("keydown.uk.offcanvas",function(a){27===a.keyCode&&i.hide()})},init:function(){var t=this;this.options=a.$.extend({target:t.element.is("a")?t.element.attr("href"):!1},this.options),this.on("click",function(a){a.preventDefault(),i.show(t.options.target)})}}),a.offcanvas=i}(UIkit); -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/core/scrollspy.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(t){"use strict";var s=t.$win,o=t.$doc,i=[],e=function(){for(var t=0;t=p)return o[t]}();if(!f)return;c.options.closest?(e.closest(r).removeClass(a),l=e.filter("a[href='#"+f.attr("id")+"']").closest(r).addClass(a)):l=e.removeClass(a).filter("a[href='#"+f.attr("id")+"']").addClass(a),c.element.trigger("inview.uk.scrollspynav",[f,l])}};this.options.smoothscroll&&t.smoothScroll&&e.each(function(){t.smoothScroll(this,c.options.smoothscroll)}),p(),this.element.data("scrollspynav",this),this.check=p,l.push(this)}})}(UIkit); -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/core/smooth-scroll.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(t){"use strict";function o(o,i){i=t.$.extend({duration:1e3,transition:"easeOutExpo",offset:0,complete:function(){}},i);var n=o.offset().top-i.offset,s=t.$doc.height(),e=window.innerHeight;n+e>s&&(n=s-e),t.$("html,body").stop().animate({scrollTop:n},i.duration,i.transition).promise().done(i.complete)}t.component("smoothScroll",{boot:function(){t.$html.on("click.smooth-scroll.uikit","[data-uk-smooth-scroll]",function(){var o=t.$(this);if(!o.data("smoothScroll")){{t.smoothScroll(o,t.Utils.options(o.attr("data-uk-smooth-scroll")))}o.trigger("click")}return!1})},init:function(){var i=this;this.on("click",function(n){n.preventDefault(),o(t.$(this.hash).length?t.$(this.hash):t.$("body"),i.options)})}}),t.Utils.scrollToElement=o,t.$.easing.easeOutExpo||(t.$.easing.easeOutExpo=function(t,o,i,n,s){return o==s?i+n:n*(-Math.pow(2,-10*o/s)+1)+i})}(UIkit); -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/core/tab.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(t){"use strict";t.component("tab",{defaults:{target:">li:not(.uk-tab-responsive, .uk-disabled)",connect:!1,active:0,animation:!1,duration:200,swiping:!0},boot:function(){t.ready(function(i){t.$("[data-uk-tab]",i).each(function(){var i=t.$(this);if(!i.data("tab")){t.tab(i,t.Utils.options(i.attr("data-uk-tab")))}})})},init:function(){var i=this;this.current=!1,this.on("click.uikit.tab",this.options.target,function(e){if(e.preventDefault(),!i.switcher||!i.switcher.animating){var s=i.find(i.options.target).not(this);s.removeClass("uk-active").blur(),i.trigger("change.uk.tab",[t.$(this).addClass("uk-active"),i.current]),i.current=t.$(this),i.options.connect||(s.attr("aria-expanded","false"),t.$(this).attr("aria-expanded","true"))}}),this.options.connect&&(this.connect=t.$(this.options.connect)),this.responsivetab=t.$('
  • ').append('
      '),this.responsivetab.dropdown=this.responsivetab.find(".uk-dropdown"),this.responsivetab.lst=this.responsivetab.dropdown.find("ul"),this.responsivetab.caption=this.responsivetab.find("a:first"),this.element.hasClass("uk-tab-bottom")&&this.responsivetab.dropdown.addClass("uk-dropdown-up"),this.responsivetab.lst.on("click.uikit.tab","a",function(e){e.preventDefault(),e.stopPropagation();var s=t.$(this);i.element.children("li:not(.uk-tab-responsive)").eq(s.data("index")).trigger("click")}),this.on("show.uk.switcher change.uk.tab",function(t,e){i.responsivetab.caption.html(e.text())}),this.element.append(this.responsivetab),this.options.connect&&(this.switcher=t.switcher(this.element,{toggle:">li:not(.uk-tab-responsive)",connect:this.options.connect,active:this.options.active,animation:this.options.animation,duration:this.options.duration,swiping:this.options.swiping})),t.dropdown(this.responsivetab,{mode:"click"}),i.trigger("change.uk.tab",[this.element.find(this.options.target).not(".uk-tab-responsive").filter(".uk-active")]),this.check(),t.$win.on("resize orientationchange",t.Utils.debounce(function(){i.element.is(":visible")&&i.check()},100)),this.on("display.uk.check",function(){i.element.is(":visible")&&i.check()})},check:function(){var i=this.element.children("li:not(.uk-tab-responsive)").removeClass("uk-hidden");if(!i.length)return this.responsivetab.addClass("uk-hidden"),void 0;var e,s,n,a=i.eq(0).offset().top+Math.ceil(i.eq(0).height()/2),o=!1;if(this.responsivetab.lst.empty(),i.each(function(){t.$(this).offset().top>a&&(o=!0)}),o)for(var r=0;r=Math.abs(n-o)?e-t>0?"Left":"Right":n-o>0?"Up":"Down"}function n(){p=null,g.last&&(void 0!==g.el&&g.el.trigger("longTap"),g={})}function o(){p&&clearTimeout(p),p=null}function i(){a&&clearTimeout(a),l&&clearTimeout(l),u&&clearTimeout(u),p&&clearTimeout(p),a=l=u=p=null,g={}}function r(e){return e.pointerType==e.MSPOINTER_TYPE_TOUCH&&e.isPrimary}if(!e.fn.swipeLeft){var a,l,u,p,c,g={},s=750;e(function(){var v,y,w,f=0,d=0;"MSGesture"in window&&(c=new MSGesture,c.target=document.body),e(document).on("MSGestureEnd gestureend",function(e){var t=e.originalEvent.velocityX>1?"Right":e.originalEvent.velocityX<-1?"Left":e.originalEvent.velocityY>1?"Down":e.originalEvent.velocityY<-1?"Up":null;t&&void 0!==g.el&&(g.el.trigger("swipe"),g.el.trigger("swipe"+t))}).on("touchstart MSPointerDown pointerdown",function(t){("MSPointerDown"!=t.type||r(t.originalEvent))&&(w="MSPointerDown"==t.type||"pointerdown"==t.type?t:t.originalEvent.touches[0],v=Date.now(),y=v-(g.last||v),g.el=e("tagName"in w.target?w.target:w.target.parentNode),a&&clearTimeout(a),g.x1=w.pageX,g.y1=w.pageY,y>0&&250>=y&&(g.isDoubleTap=!0),g.last=v,p=setTimeout(n,s),!c||"MSPointerDown"!=t.type&&"pointerdown"!=t.type&&"touchstart"!=t.type||c.addPointer(t.originalEvent.pointerId))}).on("touchmove MSPointerMove pointermove",function(e){("MSPointerMove"!=e.type||r(e.originalEvent))&&(w="MSPointerMove"==e.type||"pointermove"==e.type?e:e.originalEvent.touches[0],o(),g.x2=w.pageX,g.y2=w.pageY,f+=Math.abs(g.x1-g.x2),d+=Math.abs(g.y1-g.y2))}).on("touchend MSPointerUp pointerup",function(n){("MSPointerUp"!=n.type||r(n.originalEvent))&&(o(),g.x2&&Math.abs(g.x1-g.x2)>30||g.y2&&Math.abs(g.y1-g.y2)>30?u=setTimeout(function(){void 0!==g.el&&(g.el.trigger("swipe"),g.el.trigger("swipe"+t(g.x1,g.x2,g.y1,g.y2))),g={}},0):"last"in g&&(isNaN(f)||30>f&&30>d?l=setTimeout(function(){var t=e.Event("tap");t.cancelTouch=i,void 0!==g.el&&g.el.trigger(t),g.isDoubleTap?(void 0!==g.el&&g.el.trigger("doubleTap"),g={}):a=setTimeout(function(){a=null,void 0!==g.el&&g.el.trigger("singleTap"),g={}},250)},0):g={},f=d=0))}).on("touchcancel MSPointerCancel",i),e(window).on("scroll",i)}),["swipe","swipeLeft","swipeRight","swipeUp","swipeDown","doubleTap","tap","singleTap","longTap"].forEach(function(t){e.fn[t]=function(n){return e(this).on(t,n)}})}}(jQuery); -------------------------------------------------------------------------------- /vendor/assets/javascripts/uikit/core/utility.min.js: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | !function(t){"use strict";var i=[];t.component("stackMargin",{defaults:{cls:"uk-margin-small-top"},boot:function(){t.ready(function(i){t.$("[data-uk-margin]",i).each(function(){var i,n=t.$(this);n.data("stackMargin")||(i=t.stackMargin(n,t.Utils.options(n.attr("data-uk-margin"))))})})},init:function(){var n=this;this.columns=[],t.$win.on("resize orientationchange",function(){var i=function(){n.process()};return t.$(function(){i(),t.$win.on("load",i)}),t.Utils.debounce(i,20)}()),t.$html.on("changed.uk.dom",function(){n.process()}),this.on("display.uk.check",function(){this.element.is(":visible")&&this.process()}.bind(this)),i.push(this)},process:function(){return this.columns=this.element.children(),t.Utils.stackMargin(this.columns,this.options),this},revert:function(){return this.columns.removeClass(this.options.cls),this}}),function(){var i=[],n=function(t){if(t.is(":visible")){var i=t.parent().width(),n=t.data("width"),s=i/n,e=Math.floor(s*t.data("height"));t.css({height:n>i?e:t.data("height")})}};t.component("responsiveElement",{defaults:{},boot:function(){t.ready(function(i){t.$("iframe.uk-responsive-width, [data-uk-responsive]",i).each(function(){var i,n=t.$(this);n.data("responsiveIframe")||(i=t.responsiveElement(n,{}))})})},init:function(){var t=this.element;t.attr("width")&&t.attr("height")&&(t.data({width:t.attr("width"),height:t.attr("height")}).on("display.uk.check",function(){n(t)}),n(t),i.push(t))}}),t.$win.on("resize load",t.Utils.debounce(function(){i.forEach(function(t){n(t)})},15))}(),t.Utils.stackMargin=function(i,n){n=t.$.extend({cls:"uk-margin-small-top"},n),n.cls=n.cls,i=t.$(i).removeClass(n.cls);var s=!1,e=i.filter(":visible:first"),a=e.length?e.position().top+e.outerHeight()-1:!1;a!==!1&&i.each(function(){var i=t.$(this);i.is(":visible")&&(s?i.addClass(n.cls):i.position().top>=a&&(s=i.addClass(n.cls)))})},t.Utils.matchHeights=function(i,n){i=t.$(i).css("min-height",""),n=t.$.extend({row:!0},n);var s=function(i){if(!(i.length<2)){var n=0;i.each(function(){n=Math.max(n,t.$(this).outerHeight())}).each(function(){var i=t.$(this),s=n-("border-box"==i.css("box-sizing")?0:i.outerHeight()-i.height());i.css("min-height",s+"px")})}};n.row?(i.first().width(),setTimeout(function(){var n=!1,e=[];i.each(function(){var i=t.$(this),a=i.offset().top;a!=n&&e.length&&(s(t.$(e)),e=[],a=i.offset().top),e.push(i),n=a}),e.length&&s(t.$(e))},0)):s(i)},function(i){t.Utils.inlineSvg=function(n,s){t.$(n||'img[src$=".svg"]',s||document).each(function(){var n=t.$(this),s=n.attr("src");if(!i[s]){var e=t.$.Deferred();t.$.get(s,{nc:Math.random()},function(i){e.resolve(t.$(i).find("svg"))}),i[s]=e.promise()}i[s].then(function(i){var s=t.$(i).clone();n.attr("id")&&s.attr("id",n.attr("id")),n.attr("class")&&s.attr("class",n.attr("class")),n.attr("style")&&s.attr("style",n.attr("style")),n.attr("width")&&(s.attr("width",n.attr("width")),n.attr("height")||s.removeAttr("height")),n.attr("height")&&(s.attr("height",n.attr("height")),n.attr("width")||s.removeAttr("width")),n.replaceWith(s)})})},t.ready(function(i){t.Utils.inlineSvg("[data-uk-svg]",i)})}({})}(UIkit); -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sai-lab/shoko/bbe01346c725ee7342956c57f2295ce1e44636d6/vendor/assets/stylesheets/.keep -------------------------------------------------------------------------------- /vendor/assets/stylesheets/highlight/tomorrow.css: -------------------------------------------------------------------------------- 1 | /* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ 2 | 3 | /* Tomorrow Comment */ 4 | .hljs-comment { 5 | color: #8e908c; 6 | } 7 | 8 | /* Tomorrow Red */ 9 | .hljs-variable, 10 | .hljs-attribute, 11 | .hljs-tag, 12 | .hljs-regexp, 13 | .ruby .hljs-constant, 14 | .xml .hljs-tag .hljs-title, 15 | .xml .hljs-pi, 16 | .xml .hljs-doctype, 17 | .html .hljs-doctype, 18 | .css .hljs-id, 19 | .css .hljs-class, 20 | .css .hljs-pseudo { 21 | color: #c82829; 22 | } 23 | 24 | /* Tomorrow Orange */ 25 | .hljs-number, 26 | .hljs-preprocessor, 27 | .hljs-pragma, 28 | .hljs-built_in, 29 | .hljs-literal, 30 | .hljs-params, 31 | .hljs-constant { 32 | color: #f5871f; 33 | } 34 | 35 | /* Tomorrow Yellow */ 36 | .ruby .hljs-class .hljs-title, 37 | .css .hljs-rule .hljs-attribute { 38 | color: #eab700; 39 | } 40 | 41 | /* Tomorrow Green */ 42 | .hljs-string, 43 | .hljs-value, 44 | .hljs-inheritance, 45 | .hljs-header, 46 | .hljs-name, 47 | .ruby .hljs-symbol, 48 | .xml .hljs-cdata { 49 | color: #718c00; 50 | } 51 | 52 | /* Tomorrow Aqua */ 53 | .hljs-title, 54 | .css .hljs-hexcolor { 55 | color: #3e999f; 56 | } 57 | 58 | /* Tomorrow Blue */ 59 | .hljs-function, 60 | .python .hljs-decorator, 61 | .python .hljs-title, 62 | .ruby .hljs-function .hljs-title, 63 | .ruby .hljs-title .hljs-keyword, 64 | .perl .hljs-sub, 65 | .javascript .hljs-title, 66 | .coffeescript .hljs-title { 67 | color: #4271ae; 68 | } 69 | 70 | /* Tomorrow Purple */ 71 | .hljs-keyword, 72 | .javascript .hljs-function { 73 | color: #8959a8; 74 | } 75 | 76 | .hljs { 77 | display: block; 78 | overflow-x: auto; 79 | background: white; 80 | color: #4d4d4c; 81 | padding: 0.5em; 82 | -webkit-text-size-adjust: none; 83 | } 84 | 85 | .coffeescript .javascript, 86 | .javascript .xml, 87 | .tex .hljs-formula, 88 | .xml .javascript, 89 | .xml .vbscript, 90 | .xml .css, 91 | .xml .hljs-cdata { 92 | opacity: 0.5; 93 | } 94 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/accordion.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-accordion-title{margin-top:0;margin-bottom:15px;padding:5px 15px;background:#f5f5f5;font-size:18px;line-height:24px;cursor:pointer;border:1px solid #ddd;border-radius:4px}.uk-accordion-content{padding:0 15px 15px 15px}.uk-accordion-content:after,.uk-accordion-content:before{content:"";display:table}.uk-accordion-content:after{clear:both}.uk-accordion-content>:last-child{margin-bottom:0} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/autocomplete.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-autocomplete{display:inline-block;position:relative;max-width:100%;vertical-align:middle}.uk-nav-autocomplete>li>a{color:#444}.uk-nav-autocomplete>li.uk-active>a{background:#00a8e6;color:#fff;outline:0;box-shadow:inset 0 0 5px rgba(0,0,0,.05);text-shadow:0 -1px 0 rgba(0,0,0,.1)}.uk-nav-autocomplete .uk-nav-header{color:#999}.uk-nav-autocomplete .uk-nav-divider{border-top:1px solid #ddd} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/datepicker.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-datepicker{z-index:1050;width:auto;-webkit-animation:uk-fade .2s ease-in-out;animation:uk-fade .2s ease-in-out;-webkit-transform-origin:0 0;transform-origin:0 0}.uk-datepicker-nav{margin-bottom:15px;text-align:center;line-height:20px}.uk-datepicker-nav:after,.uk-datepicker-nav:before{content:"";display:table}.uk-datepicker-nav:after{clear:both}.uk-datepicker-nav a{color:#444;text-decoration:none}.uk-datepicker-nav a:hover{color:#444}.uk-datepicker-previous{float:left}.uk-datepicker-next{float:right}.uk-datepicker-next:after,.uk-datepicker-previous:after{width:20px;font-family:FontAwesome}.uk-datepicker-previous:after{content:"\f053"}.uk-datepicker-next:after{content:"\f054"}.uk-datepicker-table{width:100%}.uk-datepicker-table td,.uk-datepicker-table th{padding:2px}.uk-datepicker-table th{font-size:12px}.uk-datepicker-table a{display:block;width:26px;line-height:24px;text-align:center;color:#444;text-decoration:none;border:1px solid transparent;border-radius:4px}a.uk-datepicker-table-muted{color:#999}.uk-datepicker-table a:focus,.uk-datepicker-table a:hover{background-color:#fafafa;color:#444;outline:0;border-color:rgba(0,0,0,.16);text-shadow:0 1px 0 #fff}.uk-datepicker-table a:active{background-color:#eee;color:#444}.uk-datepicker-table a.uk-active{background:#00a8e6;color:#fff;box-shadow:inset 0 0 5px rgba(0,0,0,.05);text-shadow:0 -1px 0 rgba(0,0,0,.1)} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/dotnav.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-dotnav{display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-wrap:wrap;-webkit-flex-wrap:wrap;flex-wrap:wrap;margin-left:-15px;margin-top:-15px;padding:0;list-style:none}.uk-dotnav>*{-ms-flex:none;-webkit-flex:none;flex:none;padding-left:15px;margin-top:15px}.uk-dotnav:after,.uk-dotnav:before{content:"";display:block;overflow:hidden}.uk-dotnav:after{clear:both}.uk-dotnav>*{float:left}.uk-dotnav>*>*{display:block;box-sizing:content-box;width:20px;height:20px;border-radius:50%;background:rgba(50,50,50,.1);text-indent:100%;overflow:hidden;white-space:nowrap;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.uk-dotnav>*>:focus,.uk-dotnav>*>:hover{background:rgba(50,50,50,.4);outline:0}.uk-dotnav>*>:active{background:rgba(50,50,50,.6)}.uk-dotnav>.uk-active>*{background:rgba(50,50,50,.4);-webkit-transform:scale(1.3);transform:scale(1.3)}.uk-dotnav-contrast>*>*{background:rgba(255,255,255,.4)}.uk-dotnav-contrast>*>:focus,.uk-dotnav-contrast>*>:hover{background:rgba(255,255,255,.7)}.uk-dotnav-contrast>*>:active{background:rgba(255,255,255,.9)}.uk-dotnav-contrast>.uk-active>*{background:rgba(255,255,255,.9)}.uk-dotnav-vertical{-ms-flex-direction:column;-webkit-flex-direction:column;flex-direction:column}.uk-dotnav-vertical>*{float:none} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/form-advanced.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-form input[type=radio],.uk-form input[type=checkbox]{display:inline-block;height:14px;width:14px;border:1px solid #aaa;overflow:hidden;margin-top:-4px;vertical-align:middle;-webkit-appearance:none;outline:0;background:0 0}.uk-form input[type=radio]{border-radius:50%}.uk-form input[type=checkbox]:before,.uk-form input[type=radio]:before{display:block}.uk-form input[type=radio]:checked:before{content:'';width:8px;height:8px;margin:2px auto 0;border-radius:50%;background:#00a8e6}.uk-form input[type=checkbox]:checked:before,.uk-form input[type=checkbox]:indeterminate:before{content:"\f00c";font-family:FontAwesome;font-size:12px;-webkit-font-smoothing:antialiased;text-align:center;line-height:12px;color:#00a8e6}.uk-form input[type=checkbox]:indeterminate:before{content:"\f068"}.uk-form input[type=checkbox]:disabled,.uk-form input[type=radio]:disabled{border-color:#ddd}.uk-form input[type=radio]:disabled:checked:before{background-color:#aaa}.uk-form input[type=checkbox]:disabled:checked:before,.uk-form input[type=checkbox]:disabled:indeterminate:before{color:#aaa} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/form-file.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-form-file{display:inline-block;vertical-align:middle;position:relative;overflow:hidden}.uk-form-file input[type=file]{position:absolute;top:0;z-index:1;width:100%;opacity:0;cursor:pointer;left:0;font-size:500px} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/form-password.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-form-password{display:inline-block;position:relative;max-width:100%}.uk-form-password-toggle{display:block;position:absolute;top:50%;right:10px;margin-top:-6px;font-size:13px;line-height:13px;color:#999}.uk-form-password-toggle:hover{color:#999;text-decoration:none}.uk-form-password>input{padding-right:50px!important} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/form-select.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-form-select{display:inline-block;vertical-align:middle;position:relative;overflow:hidden}.uk-form-select select{position:absolute;top:0;z-index:1;width:100%;height:100%;opacity:0;cursor:pointer;left:0;-webkit-appearance:none} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/htmleditor.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-htmleditor-navbar{background:#f5f5f5;border:1px solid rgba(0,0,0,.06);border-top-left-radius:4px;border-top-right-radius:4px}.uk-htmleditor-navbar:after,.uk-htmleditor-navbar:before{content:"";display:table}.uk-htmleditor-navbar:after{clear:both}.uk-htmleditor-navbar-nav{margin:0;padding:0;list-style:none;float:left}.uk-htmleditor-navbar-nav>li{float:left}.uk-htmleditor-navbar-nav>li>a{display:block;box-sizing:border-box;text-decoration:none;height:41px;padding:0 15px;line-height:40px;color:#444;font-size:11px;cursor:pointer;margin-top:-1px;margin-left:-1px;border:1px solid transparent;border-bottom-width:0;text-shadow:0 1px 0 #fff}.uk-htmleditor-navbar-nav>li:hover>a,.uk-htmleditor-navbar-nav>li>a:focus{background-color:#fafafa;color:#444;outline:0;position:relative;z-index:1;border-left-color:rgba(0,0,0,.1);border-right-color:rgba(0,0,0,.1);border-top-color:rgba(0,0,0,.1)}.uk-htmleditor-navbar-nav>li>a:active{background-color:#eee;color:#444;border-left-color:rgba(0,0,0,.1);border-right-color:rgba(0,0,0,.1);border-top-color:rgba(0,0,0,.2)}.uk-htmleditor-navbar-nav>li.uk-active>a{background-color:#fafafa;color:#444;border-left-color:rgba(0,0,0,.1);border-right-color:rgba(0,0,0,.1);border-top-color:rgba(0,0,0,.1)}.uk-htmleditor-navbar-flip{float:right}[data-mode=split] .uk-htmleditor-button-code,[data-mode=split] .uk-htmleditor-button-preview{display:none}.uk-htmleditor-content{border-left:1px solid #ddd;border-right:1px solid #ddd;border-bottom:1px solid #ddd;background:#fff;border-bottom-left-radius:4px;border-bottom-right-radius:4px}.uk-htmleditor-content:after,.uk-htmleditor-content:before{content:"";display:table}.uk-htmleditor-content:after{clear:both}.uk-htmleditor-fullscreen{position:fixed;top:0;left:0;right:0;bottom:0;z-index:990}.uk-htmleditor-fullscreen .uk-htmleditor-content{position:absolute;top:41px;left:0;right:0;bottom:0}.uk-htmleditor-fullscreen .uk-icon-expand:before{content:"\f066"}.uk-htmleditor-code,.uk-htmleditor-preview{box-sizing:border-box}.uk-htmleditor-preview{padding:20px;overflow-y:scroll;position:relative}[data-mode=tab][data-active-tab=code] .uk-htmleditor-preview,[data-mode=tab][data-active-tab=preview] .uk-htmleditor-code{display:none}[data-mode=split] .uk-htmleditor-code,[data-mode=split] .uk-htmleditor-preview{float:left;width:50%}[data-mode=split] .uk-htmleditor-code{border-right:1px solid #eee}.uk-htmleditor-iframe{position:absolute;top:0;left:0;width:100%;height:100%}.uk-htmleditor .CodeMirror{padding:10px;box-sizing:border-box}.uk-htmleditor-navbar-nav:first-child>li:first-child>a{border-top-left-radius:4px}.uk-htmleditor-navbar-flip .uk-htmleditor-navbar-nav>li>a{margin-left:0;margin-right:-1px}.uk-htmleditor-navbar-flip .uk-htmleditor-navbar-nav:first-child>li:first-child>a{border-top-left-radius:0}.uk-htmleditor-navbar-flip .uk-htmleditor-navbar-nav:last-child>li:last-child>a{border-top-right-radius:4px}.uk-htmleditor-fullscreen .uk-htmleditor-navbar{border-top:none;border-left:none;border-right:none;border-radius:0}.uk-htmleditor-fullscreen .uk-htmleditor-content{border:none;border-radius:0}.uk-htmleditor-fullscreen .uk-htmleditor-navbar-nav>li>a{border-radius:0!important} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/nestable.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-nestable{padding:0;list-style:none}.uk-nestable a,.uk-nestable img{-webkit-touch-callout:none}.uk-nestable-list{margin:0;padding-left:40px;list-style:none}.uk-nestable-item{touch-action:none}.uk-nestable-item+.uk-nestable-item{margin-top:10px}.uk-nestable-list:not(.uk-nestable-dragged)>.uk-nestable-item:first-child{margin-top:10px}.uk-nestable-dragged{position:absolute;z-index:1050;pointer-events:none;padding-left:0}.uk-nestable-placeholder{position:relative}.uk-nestable-placeholder>*{opacity:0}.uk-nestable-placeholder:after{content:'';position:absolute;top:0;bottom:0;left:0;right:0;border:1px dashed #ddd;opacity:1}.uk-nestable-empty{min-height:30px}.uk-nestable-handle{touch-action:none}.uk-nestable-handle:hover{cursor:move}.uk-nestable-moving,.uk-nestable-moving *{cursor:move}[data-nestable-action=toggle]{cursor:pointer;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.uk-nestable-toggle{display:inline-block;visibility:hidden}.uk-nestable-toggle:after{content:"\f147";font-family:FontAwesome}.uk-parent>:not(.uk-nestable-list) .uk-nestable-toggle{visibility:visible}.uk-collapsed .uk-nestable-list{display:none}.uk-collapsed .uk-nestable-toggle:after{content:"\f196"}.uk-nestable-panel{padding:5px;background:#f5f5f5;border-radius:4px;border:1px solid rgba(0,0,0,.06);text-shadow:0 1px 0 #fff} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/notify.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-notify{position:fixed;top:10px;left:10px;z-index:1040;box-sizing:border-box;width:350px}.uk-notify-bottom-right,.uk-notify-top-right{left:auto;right:10px}.uk-notify-bottom-center,.uk-notify-top-center{left:50%;margin-left:-175px}.uk-notify-bottom-center,.uk-notify-bottom-left,.uk-notify-bottom-right{top:auto;bottom:10px}@media (max-width:479px){.uk-notify{left:10px;right:10px;width:auto;margin:0}}.uk-notify-message{position:relative;margin-bottom:10px;padding:15px;background:#444;color:#fff;font-size:16px;line-height:22px;cursor:pointer;border:1px solid #444;border-radius:4px}.uk-notify-message>.uk-close{visibility:hidden;float:right}.uk-notify-message:hover>.uk-close{visibility:visible}.uk-notify-message-primary{background:#ebf7fd;color:#2d7091;border-color:rgba(45,112,145,.3)}.uk-notify-message-success{background:#f2fae3;color:#659f13;border-color:rgba(101,159,19,.3)}.uk-notify-message-warning{background:#fffceb;color:#e28327;border-color:rgba(226,131,39,.3)}.uk-notify-message-danger{background:#fff1f0;color:#d85030;border-color:rgba(216,80,48,.3)} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/placeholder.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-placeholder{margin-bottom:15px;padding:15px;border:1px dashed #ddd;background:#fafafa;color:#444}*+.uk-placeholder{margin-top:15px}.uk-placeholder>:last-child{margin-bottom:0}.uk-placeholder-large{padding-top:80px;padding-bottom:80px} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/progress.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-progress{box-sizing:border-box;height:20px;margin-bottom:15px;background:#f5f5f5;overflow:hidden;line-height:20px;box-shadow:inset 0 0 0 1px rgba(0,0,0,.06);border-radius:4px}*+.uk-progress{margin-top:15px}.uk-progress-bar{width:0;height:100%;background:#00a8e6;float:left;-webkit-transition:width .6s ease;transition:width .6s ease;font-size:12px;color:#fff;text-align:center;box-shadow:inset 0 0 5px rgba(0,0,0,.05);text-shadow:0 -1px 0 rgba(0,0,0,.1)}.uk-progress-mini{height:6px}.uk-progress-small{height:12px}.uk-progress-success .uk-progress-bar{background-color:#8cc14c}.uk-progress-warning .uk-progress-bar{background-color:#faa732}.uk-progress-danger .uk-progress-bar{background-color:#da314b}.uk-progress-striped .uk-progress-bar{background-image:-webkit-linear-gradient(-45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(-45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:30px 30px}.uk-progress-striped.uk-active .uk-progress-bar{-webkit-animation:uk-progress-bar-stripes 2s linear infinite;animation:uk-progress-bar-stripes 2s linear infinite}@-webkit-keyframes uk-progress-bar-stripes{0%{background-position:0 0}100%{background-position:30px 0}}@keyframes uk-progress-bar-stripes{0%{background-position:0 0}100%{background-position:30px 0}}.uk-progress-mini,.uk-progress-small{border-radius:500px} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/search.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-search{display:inline-block;position:relative;margin:0}.uk-search:before{content:"\f002";position:absolute;top:0;left:0;width:30px;line-height:30px;text-align:center;font-family:FontAwesome;font-size:14px;color:rgba(0,0,0,.2)}.uk-search-field::-moz-focus-inner{border:0;padding:0}.uk-search-field::-webkit-search-cancel-button,.uk-search-field::-webkit-search-decoration{-webkit-appearance:none}.uk-search-field::-ms-clear{display:none}.uk-search-field::-moz-placeholder{opacity:1}.uk-search-field{box-sizing:border-box;margin:0;border-radius:0;font:inherit;color:#444;-webkit-appearance:none;width:120px;height:30px;padding:0 0 0 30px;border:1px solid transparent;background:transparent;-webkit-transition:all linear .2s;transition:all linear .2s;vertical-align:middle}.uk-search-field:-ms-input-placeholder{color:#999!important}.uk-search-field::-moz-placeholder{color:#999}.uk-search-field::-webkit-input-placeholder{color:#999}.uk-search-field:focus{outline:0}.uk-search-field:focus,.uk-search.uk-active .uk-search-field{width:180px}.uk-dropdown-search{width:300px;margin-top:0;background:#fff;color:#444}.uk-open>.uk-dropdown-search{-webkit-animation:uk-slide-top-fixed .2s ease-in-out;animation:uk-slide-top-fixed .2s ease-in-out}.uk-navbar-flip .uk-dropdown-search{margin-top:12px;margin-right:-16px}.uk-nav-search>li>a{color:#444}.uk-nav-search>li.uk-active>a{background:#00a8e6;color:#fff;outline:0;box-shadow:inset 0 0 5px rgba(0,0,0,.05);text-shadow:0 -1px 0 rgba(0,0,0,.1)}.uk-nav-search .uk-nav-header{color:#999}.uk-nav-search .uk-nav-divider{border-top:1px solid #ddd}.uk-nav-search ul a{color:#07d}.uk-nav-search ul a:hover{color:#059}.uk-offcanvas .uk-search{display:block;margin:20px 15px}.uk-offcanvas .uk-search:before{color:#777}.uk-offcanvas .uk-search-field{width:100%;border-color:transparent;background:#1a1a1a;color:#ccc}.uk-offcanvas .uk-search-field:-ms-input-placeholder{color:#777!important}.uk-offcanvas .uk-search-field::-moz-placeholder{color:#777}.uk-offcanvas .uk-search-field::-webkit-input-placeholder{color:#777} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/slidenav.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-slidenav{display:inline-block;box-sizing:border-box;width:60px;height:60px;line-height:60px;color:rgba(50,50,50,.4);font-size:60px;text-align:center}.uk-slidenav:focus,.uk-slidenav:hover{outline:0;text-decoration:none;color:rgba(50,50,50,.7);cursor:pointer}.uk-slidenav:active{color:rgba(50,50,50,.9)}.uk-slidenav-previous:before{content:"\f104";font-family:FontAwesome}.uk-slidenav-next:before{content:"\f105";font-family:FontAwesome}.uk-slidenav-position{position:relative}.uk-slidenav-position .uk-slidenav{display:none;position:absolute;top:50%;z-index:1;margin-top:-30px}.uk-slidenav-position:hover .uk-slidenav{display:block}.uk-slidenav-position .uk-slidenav-previous{left:20px}.uk-slidenav-position .uk-slidenav-next{right:20px}.uk-slidenav-contrast{color:rgba(255,255,255,.5)}.uk-slidenav-contrast:focus,.uk-slidenav-contrast:hover{color:rgba(255,255,255,.7)}.uk-slidenav-contrast:active{color:rgba(255,255,255,.9)} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/slider.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-slider{position:relative;z-index:0;touch-action:pan-y}.uk-slider:not(.uk-grid){margin:0;padding:0;list-style:none}.uk-slider>*{position:absolute;top:0;left:0}.uk-slider-container{overflow:hidden}.uk-slider:not(.uk-drag){-webkit-transition:-webkit-transform 200ms linear;transition:transform 200ms linear}.uk-slider.uk-drag{cursor:col-resize;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.uk-slider a,.uk-slider img{-webkit-user-drag:none;user-drag:none;-webkit-touch-callout:none}.uk-slider img{pointer-events:none}.uk-slider-fullscreen,.uk-slider-fullscreen>li{height:100vh} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/slideshow.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-slideshow{position:relative;z-index:0;width:100%;margin:0;padding:0;list-style:none;overflow:hidden;touch-action:pan-y}.uk-slideshow>li{position:absolute;top:0;left:0;width:100%;opacity:0}.uk-slideshow>.uk-active{z-index:10;opacity:1}.uk-slideshow>li>img{visibility:hidden}[data-uk-slideshow-slide]{cursor:pointer}.uk-slideshow-fullscreen,.uk-slideshow-fullscreen>li{height:100vh}.uk-slideshow-fade-out{-webkit-animation:uk-fade .5s linear reverse;animation:uk-fade .5s linear reverse}.uk-slideshow-scroll-forward-in{-webkit-animation:uk-slide-right .5s ease-in-out;animation:uk-slide-right .5s ease-in-out}.uk-slideshow-scroll-forward-out{-webkit-animation:uk-slide-left .5s ease-in-out reverse;animation:uk-slide-left .5s ease-in-out reverse}.uk-slideshow-scroll-backward-in{-webkit-animation:uk-slide-left .5s ease-in-out;animation:uk-slide-left .5s ease-in-out}.uk-slideshow-scroll-backward-out{-webkit-animation:uk-slide-right .5s ease-in-out reverse;animation:uk-slide-right .5s ease-in-out reverse}.uk-slideshow-scale-out{-webkit-animation:uk-fade-scale-15 .5s ease-in-out reverse;animation:uk-fade-scale-15 .5s ease-in-out reverse}.uk-slideshow-swipe-forward-in{-webkit-animation:uk-slide-left-33 .5s ease-in-out;animation:uk-slide-left-33 .5s ease-in-out}.uk-slideshow-swipe-forward-out{-webkit-animation:uk-slide-left .5s ease-in-out reverse;animation:uk-slide-left .5s ease-in-out reverse}.uk-slideshow-swipe-backward-in{-webkit-animation:uk-slide-right-33 .5s ease-in-out;animation:uk-slide-right-33 .5s ease-in-out}.uk-slideshow-swipe-backward-out{-webkit-animation:uk-slide-right .5s ease-in-out reverse;animation:uk-slide-right .5s ease-in-out reverse}.uk-slideshow-swipe-backward-in:before,.uk-slideshow-swipe-forward-in:before{content:'';position:absolute;top:0;bottom:0;left:0;right:0;z-index:1;background:rgba(0,0,0,.6);-webkit-animation:uk-fade .5s ease-in-out reverse;animation:uk-fade .5s ease-in-out reverse} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/sortable.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-sortable{position:relative}.uk-sortable>*{touch-action:none}.uk-sortable a,.uk-sortable img{-webkit-touch-callout:none}.uk-sortable>:last-child{margin-bottom:0}.uk-sortable-dragged{position:absolute;z-index:1050;pointer-events:none}.uk-sortable-placeholder{opacity:0}.uk-sortable-empty{min-height:30px}.uk-sortable-handle{touch-action:none}.uk-sortable-handle:hover{cursor:move}.uk-sortable-moving,.uk-sortable-moving *{cursor:move} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/sticky.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | [data-uk-sticky].uk-active{z-index:980;box-sizing:border-box}.uk-sticky-placeholder>*{-webkit-backface-visibility:hidden;backface-visibility:hidden}[data-uk-sticky][class*=uk-animation-]{-webkit-animation-duration:.2s;animation-duration:.2s}[data-uk-sticky].uk-animation-reverse{-webkit-animation-duration:.2s;animation-duration:.2s} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/tooltip.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-tooltip{display:none;position:absolute;z-index:1030;box-sizing:border-box;max-width:200px;padding:5px 8px;background:#333;color:rgba(255,255,255,.7);font-size:12px;line-height:18px;border-radius:3px;text-shadow:0 1px 0 rgba(0,0,0,.5)}.uk-tooltip:after{content:"";display:block;position:absolute;width:0;height:0;border:5px dashed #333}.uk-tooltip-top-left:after,.uk-tooltip-top-right:after,.uk-tooltip-top:after{bottom:-5px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent;border-top-color:#333}.uk-tooltip-bottom-left:after,.uk-tooltip-bottom-right:after,.uk-tooltip-bottom:after{top:-5px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent;border-bottom-color:#333}.uk-tooltip-bottom:after,.uk-tooltip-top:after{left:50%;margin-left:-5px}.uk-tooltip-bottom-left:after,.uk-tooltip-top-left:after{left:10px}.uk-tooltip-bottom-right:after,.uk-tooltip-top-right:after{right:10px}.uk-tooltip-left:after{right:-5px;top:50%;margin-top:-5px;border-left-style:solid;border-right:none;border-top-color:transparent;border-bottom-color:transparent;border-left-color:#333}.uk-tooltip-right:after{left:-5px;top:50%;margin-top:-5px;border-right-style:solid;border-left:none;border-top-color:transparent;border-bottom-color:transparent;border-right-color:#333} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/uikit/components/upload.almost-flat.min.css: -------------------------------------------------------------------------------- 1 | /*! UIkit 2.23.0 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */ 2 | .uk-dragover{box-shadow:0 0 20px rgba(100,100,100,.3)} --------------------------------------------------------------------------------