├── log └── .keep ├── app ├── mailers │ └── .keep ├── models │ ├── .keep │ ├── concerns │ │ └── .keep │ ├── micropost.rb │ └── user.rb ├── assets │ ├── images │ │ └── .keep │ ├── stylesheets │ │ ├── docs.scss │ │ └── application.css │ └── javascripts │ │ ├── docs.coffee │ │ └── application.js ├── controllers │ ├── concerns │ │ └── .keep │ ├── api │ │ ├── v2 │ │ │ └── users_controller.rb │ │ └── v1 │ │ │ ├── microposts_controller.rb │ │ │ ├── sessions_controller.rb │ │ │ ├── users_controller.rb │ │ │ └── base_controller.rb │ ├── application_controller.rb │ └── docs_controller.rb ├── helpers │ ├── docs_helper.rb │ ├── api │ │ ├── v2 │ │ │ └── users_helper.rb │ │ └── v1 │ │ │ ├── sessions_helper.rb │ │ │ └── microposts_helper.rb │ └── application_helper.rb ├── docs │ └── slate │ │ ├── .travis.yml │ │ ├── Rakefile │ │ ├── source │ │ ├── javascripts │ │ │ ├── all.js │ │ │ ├── all_nosearch.js │ │ │ ├── app │ │ │ │ ├── toc.js │ │ │ │ ├── search.js │ │ │ │ └── lang.js │ │ │ └── lib │ │ │ │ ├── jquery.highlight.js │ │ │ │ ├── energize.js │ │ │ │ ├── jquery_ui.js │ │ │ │ └── jquery.tocify.js │ │ ├── images │ │ │ ├── logo.png │ │ │ └── navbar.png │ │ ├── fonts │ │ │ ├── icomoon.eot │ │ │ ├── icomoon.ttf │ │ │ ├── icomoon.woff │ │ │ └── icomoon.svg │ │ ├── index.md │ │ ├── stylesheets │ │ │ ├── _syntax.scss.erb │ │ │ ├── _icon-font.scss │ │ │ ├── print.css.scss │ │ │ ├── _variables.scss │ │ │ ├── _normalize.css │ │ │ └── screen.css.scss │ │ ├── includes │ │ │ └── _errors.md │ │ └── layouts │ │ │ └── layout.erb │ │ ├── .gitignore │ │ ├── Gemfile │ │ ├── Dockerfile │ │ ├── CONTRIBUTING.md │ │ ├── LICENSE │ │ ├── CHANGELOG.md │ │ ├── config.rb │ │ ├── Gemfile.lock │ │ └── README.md ├── views │ ├── api │ │ ├── v1 │ │ │ ├── users │ │ │ │ ├── update.json.jbuilder │ │ │ │ └── show.json.jbuilder │ │ │ ├── sessions │ │ │ │ └── create.json.jbuilder │ │ │ └── microposts │ │ │ │ └── index.json.jbuilder │ │ └── v2 │ │ │ └── users │ │ │ └── show.json.jbuilder │ ├── layouts │ │ └── application.html.erb │ └── docs │ │ └── index.html └── policies │ ├── user_policy.rb │ └── application_policy.rb ├── lib ├── assets │ └── .keep └── tasks │ ├── .keep │ ├── docs.rake │ └── data.rake ├── public ├── favicon.ico ├── robots.txt ├── 500.html ├── 422.html └── 404.html ├── test ├── helpers │ └── .keep ├── mailers │ └── .keep ├── models │ ├── .keep │ ├── user_test.rb │ └── micropost_test.rb ├── controllers │ ├── .keep │ ├── docs_controller_test.rb │ └── api │ │ ├── v2 │ │ └── users_controller_test.rb │ │ └── v1 │ │ ├── sessions_controller_test.rb │ │ └── microposts_controller_test.rb ├── fixtures │ ├── .keep │ ├── users.yml │ └── microposts.yml ├── integration │ └── .keep └── test_helper.rb ├── vendor └── assets │ ├── javascripts │ └── .keep │ └── stylesheets │ └── .keep ├── bin ├── bundle ├── rake ├── rails ├── spring └── setup ├── config ├── boot.rb ├── initializers │ ├── cookies_serializer.rb │ ├── session_store.rb │ ├── mime_types.rb │ ├── filter_parameter_logging.rb │ ├── backtrace_silencers.rb │ ├── assets.rb │ ├── wrap_parameters.rb │ └── inflections.rb ├── environment.rb ├── database.yml ├── locales │ └── en.yml ├── routes.rb ├── secrets.yml ├── application.rb └── environments │ ├── development.rb │ ├── test.rb │ └── production.rb ├── config.ru ├── db ├── migrate │ ├── 20150502134614_add_password_digest_to_users.rb │ ├── 20150502123451_add_authentication_token_to_users.rb │ ├── 20150503131743_create_microposts.rb │ └── 20150502072954_create_users.rb ├── seeds.rb └── schema.rb ├── docs_build.sh ├── Rakefile ├── .gitignore ├── README.rdoc ├── spec ├── controllers │ └── users_controller_spec.rb └── spec_helper.rb ├── Gemfile └── Gemfile.lock /log/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/mailers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/models/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/assets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/helpers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/mailers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/models/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/controllers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/integration/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/tasks/docs.rake: -------------------------------------------------------------------------------- 1 | namespace :docs do 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/docs_helper.rb: -------------------------------------------------------------------------------- 1 | module DocsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/docs/slate/.travis.yml: -------------------------------------------------------------------------------- 1 | rvm: 2 | - 1.9.3 3 | - 2.0.0 4 | -------------------------------------------------------------------------------- /app/models/micropost.rb: -------------------------------------------------------------------------------- 1 | class Micropost < ActiveRecord::Base 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/api/v2/users_helper.rb: -------------------------------------------------------------------------------- 1 | module Api::V2::UsersHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/api/v1/sessions_helper.rb: -------------------------------------------------------------------------------- 1 | module Api::V1::SessionsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/api/v1/microposts_helper.rb: -------------------------------------------------------------------------------- 1 | module Api::V1::MicropostsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/docs/slate/Rakefile: -------------------------------------------------------------------------------- 1 | require 'middleman-gh-pages' 2 | 3 | task :default => [:build] 4 | -------------------------------------------------------------------------------- /app/docs/slate/source/javascripts/all.js: -------------------------------------------------------------------------------- 1 | //= require_tree ./lib 2 | //= require_tree ./app 3 | -------------------------------------------------------------------------------- /app/views/api/v1/users/update.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.user do 2 | json.(@user, :id, :name) 3 | end 4 | -------------------------------------------------------------------------------- /app/docs/slate/source/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baya/build-an-api-rails-demo/HEAD/app/docs/slate/source/images/logo.png -------------------------------------------------------------------------------- /app/docs/slate/source/fonts/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baya/build-an-api-rails-demo/HEAD/app/docs/slate/source/fonts/icomoon.eot -------------------------------------------------------------------------------- /app/docs/slate/source/fonts/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baya/build-an-api-rails-demo/HEAD/app/docs/slate/source/fonts/icomoon.ttf -------------------------------------------------------------------------------- /app/docs/slate/source/images/navbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baya/build-an-api-rails-demo/HEAD/app/docs/slate/source/images/navbar.png -------------------------------------------------------------------------------- /app/docs/slate/source/fonts/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baya/build-an-api-rails-demo/HEAD/app/docs/slate/source/fonts/icomoon.woff -------------------------------------------------------------------------------- /app/views/api/v1/users/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.user do 2 | json.(@user, :id, :email, :name, :activated, :admin, :created_at, :updated_at) 3 | end 4 | -------------------------------------------------------------------------------- /app/views/api/v2/users/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.user do 2 | json.(@user, :id, :email, :name, :activated, :admin, :created_at, :updated_at) 3 | end 4 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /app/views/api/v1/sessions/create.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.session do 2 | json.(@user, :id, :name, :admin) 3 | json.token @user.authentication_token 4 | end 5 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/docs/slate/source/javascripts/all_nosearch.js: -------------------------------------------------------------------------------- 1 | //= require_tree ./lib 2 | //= require_tree ./app 3 | //= stub ./app/search.js 4 | //= stub ./lib/lunr.js 5 | -------------------------------------------------------------------------------- /test/models/user_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class UserTest < ActiveSupport::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rails.application 5 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/models/micropost_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class MicropostTest < ActiveSupport::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /app/controllers/api/v2/users_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::V2::UsersController < Api::V1::UsersController 2 | 3 | def show 4 | @user = User.find(params[:id]) 5 | end 6 | 7 | end 8 | -------------------------------------------------------------------------------- /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/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: '_build-an-api-rails-demo_session' 4 | -------------------------------------------------------------------------------- /test/controllers/docs_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class DocsControllerTest < ActionController::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path("../spring", __FILE__) 4 | rescue LoadError 5 | end 6 | require_relative '../config/boot' 7 | require 'rake' 8 | Rake.application.run 9 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /db/migrate/20150502134614_add_password_digest_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddPasswordDigestToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :password_digest, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /test/controllers/api/v2/users_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class Api::V2::UsersControllerTest < ActionController::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/docs.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the docs controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /db/migrate/20150502123451_add_authentication_token_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddAuthenticationTokenToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :authentication_token, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /test/controllers/api/v1/sessions_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class Api::V1::SessionsControllerTest < ActionController::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /docs_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | app_dir=`pwd` 4 | cd $app_dir/app/docs/slate 5 | 6 | bundle exec middleman build --clean 7 | 8 | cd $app_dir 9 | 10 | mv $app_dir/public/docs/index.html $app_dir/app/views/docs 11 | -------------------------------------------------------------------------------- /test/controllers/api/v1/microposts_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class Api::V1::MicropostsControllerTest < ActionController::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/controllers/api/v1/microposts_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::V1::MicropostsController < Api::V1::BaseController 2 | 3 | def index 4 | user = User.find(params[:user_id]) 5 | @microposts = paginate(user.microposts) 6 | end 7 | 8 | end 9 | -------------------------------------------------------------------------------- /app/assets/javascripts/docs.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 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 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path("../spring", __FILE__) 4 | rescue LoadError 5 | end 6 | APP_PATH = File.expand_path('../../config/application', __FILE__) 7 | require_relative '../config/boot' 8 | require 'rails/commands' 9 | -------------------------------------------------------------------------------- /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 | end 6 | -------------------------------------------------------------------------------- /app/views/api/v1/microposts/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.paginate_meta do 2 | paginate_meta_attributes(json, @microposts) 3 | end 4 | json.microposts do 5 | json.array! @microposts do |micropost| 6 | json.(micropost, :id, :title, :content) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/tasks/data.rake: -------------------------------------------------------------------------------- 1 | namespace :data do 2 | task :create_microposts => [:environment] do 3 | user = User.find(1) 4 | 100.times do |i| 5 | Micropost.create(user_id: user.id, title: "title-#{i}", content: "content-#{i}") 6 | end 7 | end 8 | end 9 | 10 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | 3 | def paginate_meta_attributes(json, object) 4 | json.(object, 5 | :current_page, 6 | :next_page, 7 | :prev_page, 8 | :total_pages, 9 | :total_count) 10 | end 11 | 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20150503131743_create_microposts.rb: -------------------------------------------------------------------------------- 1 | class CreateMicroposts < ActiveRecord::Migration 2 | def change 3 | create_table :microposts do |t| 4 | t.string :title 5 | t.text :content 6 | t.integer :user_id 7 | t.timestamps null: false 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/docs/slate/.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | coverage 6 | InstalledFiles 7 | lib/bundler/man 8 | pkg 9 | rdoc 10 | spec/reports 11 | test/tmp 12 | test/version_tmp 13 | tmp 14 | *.DS_STORE 15 | build/ 16 | .cache 17 | 18 | # YARD artifacts 19 | .yardoc 20 | _yardoc 21 | doc/ 22 | .idea/ -------------------------------------------------------------------------------- /app/docs/slate/Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | # Middleman 4 | gem 'middleman', '~>3.3.10' 5 | gem 'middleman-gh-pages', '~> 0.0.3' 6 | gem 'middleman-syntax', '~> 2.0.0' 7 | gem 'rouge', '~> 1.8.0' 8 | gem 'redcarpet', '~> 3.2.2' 9 | 10 | gem 'rake', '~> 10.4.2' 11 | gem 'therubyracer', '~> 0.12.1', platforms: :ruby 12 | -------------------------------------------------------------------------------- /db/migrate/20150502072954_create_users.rb: -------------------------------------------------------------------------------- 1 | class CreateUsers < ActiveRecord::Migration 2 | def change 3 | create_table :users do |t| 4 | t.string :email 5 | t.string :name 6 | t.datetime :activated 7 | t.boolean :admin, default: false 8 | t.timestamps null: false 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV['RAILS_ENV'] ||= 'test' 2 | require File.expand_path('../../config/environment', __FILE__) 3 | require 'rails/test_help' 4 | 5 | class ActiveSupport::TestCase 6 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. 7 | fixtures :all 8 | 9 | # Add more helper methods to be used by all tests here... 10 | end 11 | -------------------------------------------------------------------------------- /app/docs/slate/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:trusty 2 | 3 | RUN apt-get update 4 | RUN apt-get install -yq ruby ruby-dev build-essential git 5 | RUN gem install --no-ri --no-rdoc bundler 6 | ADD Gemfile /app/Gemfile 7 | ADD Gemfile.lock /app/Gemfile.lock 8 | RUN cd /app; bundle install 9 | ADD . /app 10 | EXPOSE 4567 11 | WORKDIR /app 12 | CMD ["bundle", "exec", "middleman", "server"] 13 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | BuildAnApiRailsDemo 5 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> 6 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> 7 | <%= csrf_meta_tags %> 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/fixtures/users.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /test/fixtures/microposts.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /app/controllers/docs_controller.rb: -------------------------------------------------------------------------------- 1 | class DocsController < ApplicationController 2 | 3 | USER_NAME, PASSWORD = 'doc_reader', '123123' 4 | 5 | before_filter :basic_authenticate 6 | 7 | layout false 8 | 9 | def index 10 | end 11 | 12 | private 13 | 14 | def basic_authenticate 15 | authenticate_or_request_with_http_basic do |user_name, password| 16 | user_name == USER_NAME && password == PASSWORD 17 | end 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ActiveRecord::Base 2 | 3 | has_secure_password 4 | 5 | has_many :microposts 6 | 7 | before_create :generate_authentication_token 8 | 9 | def generate_authentication_token 10 | loop do 11 | self.authentication_token = SecureRandom.base64(64) 12 | break if !User.find_by(authentication_token: authentication_token) 13 | end 14 | end 15 | 16 | def reset_auth_token! 17 | generate_authentication_token 18 | save 19 | end 20 | 21 | end 22 | -------------------------------------------------------------------------------- /bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This file loads spring without using Bundler, in order to be fast. 4 | # It gets overwritten when you run the `spring binstub` command. 5 | 6 | unless defined?(Spring) 7 | require "rubygems" 8 | require "bundler" 9 | 10 | if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m) 11 | Gem.paths = { "GEM_PATH" => [Bundler.bundle_path.to_s, *Gem.path].uniq } 12 | gem "spring", match[1] 13 | require "spring/binstub" 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/policies/user_policy.rb: -------------------------------------------------------------------------------- 1 | class UserPolicy < ApplicationPolicy 2 | 3 | def show? 4 | return true 5 | end 6 | 7 | def create? 8 | return true 9 | end 10 | 11 | def update? 12 | return true if user.admin? 13 | return true if record.id == user.id 14 | end 15 | 16 | def destroy? 17 | return true if user.admin? 18 | return true if record.id == user.id 19 | end 20 | 21 | class Scope < ApplicationPolicy::Scope 22 | def resolve 23 | scope.all 24 | end 25 | end 26 | 27 | end 28 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.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 | 10 | # Ignore the default SQLite database. 11 | /db/*.sqlite3 12 | /db/*.sqlite3-journal 13 | 14 | # Ignore all logfiles and tempfiles. 15 | /log/* 16 | !/log/.keep 17 | /tmp 18 | public/docs/* 19 | .rspec 20 | -------------------------------------------------------------------------------- /app/docs/slate/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Slate 2 | 3 | Thanks for contributing to Slate! A couple of quick guidelines for submitting PRs: 4 | 5 | - Please point your pull requests at the `dev` branch, and keep your commit messages clear and informative. 6 | - Please make sure your contributions work in the most recent version of Chrome, Firefox, and IE. 7 | - If you're implementing a new feature, even if it's relatively small, it's nice to open an issue before you start so that others know what you're working on and can help make sure you're on the right track. 8 | 9 | Thanks again! Happy coding. -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | == README 2 | 3 | This README would normally document whatever steps are necessary to get the 4 | application up and running. 5 | 6 | Things you may want to cover: 7 | 8 | * Ruby version 9 | 10 | * System dependencies 11 | 12 | * Configuration 13 | 14 | * Database creation 15 | 16 | * Database initialization 17 | 18 | * How to run the test suite 19 | 20 | * Services (job queues, cache servers, search engines, etc.) 21 | 22 | * Deployment instructions 23 | 24 | * ... 25 | 26 | 27 | Please feel free to use a different markup language if you do not plan to run 28 | rake doc:app. 29 | -------------------------------------------------------------------------------- /app/docs/slate/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2008-2013 Concur Technologies, Inc. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | not use this file except in compliance with the License. You may obtain 5 | a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | License for the specific language governing permissions and limitations 13 | under the License. -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: db/production.sqlite3 26 | -------------------------------------------------------------------------------- /app/controllers/api/v1/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | class Api::V1::SessionsController < Api::V1::BaseController 3 | 4 | def create 5 | @user = User.find_by(email: create_params[:email]) 6 | if @user && @user.authenticate(create_params[:password]) 7 | self.current_user = @user 8 | # 我们使用 jbuilder 9 | # render( 10 | # json: Api::V1::SessionSerializer.new(user, root: false).to_json, 11 | # status: 201 12 | # ) 13 | else 14 | return api_error(status: 401) 15 | end 16 | end 17 | 18 | private 19 | 20 | def create_params 21 | params.require(:user).permit(:email, :password) 22 | end 23 | 24 | end 25 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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_ujs 15 | //= require turbolinks 16 | //= require_tree . 17 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any styles 10 | * defined in the other CSS/SCSS files in this directory. It is generally better to create a new 11 | * file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /app/controllers/api/v1/users_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::V1::UsersController < Api::V1::BaseController 2 | 3 | before_action :authenticate_user!, only: [:update] 4 | 5 | def show 6 | @user = User.find(params[:id]) 7 | 8 | Rails.logger.info("---------------------#{@user.inspect}") 9 | 10 | # render(json: Api::V1::UserSerializer.new(user).to_json) 11 | # render json: @user.to_json 12 | end 13 | 14 | def update 15 | @user = User.find(params[:id]) 16 | # return api_error(status: 403) if !UserPolicy.new(current_user, @user).update? 17 | authorize @user, :update? 18 | @user.update_attributes(update_params) 19 | end 20 | 21 | private 22 | 23 | def update_params 24 | params.require(:user).permit(:name) 25 | end 26 | 27 | end 28 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | 3 | namespace :api do 4 | namespace :v1 do 5 | resources :users, only: [:index, :create, :show, :update, :destroy] 6 | # resources :microposts, only: [:index, :create, :show, :update, :destroy] 7 | resources :sessions, only: [:create] 8 | scope path: '/user/:user_id' do 9 | resources :microposts, only: [:index] 10 | end 11 | end 12 | 13 | namespace :v2 do 14 | resources :users, only: [:index, :create, :show, :update, :destroy] 15 | resources :sessions, only: [:create] 16 | scope path: '/user/:user_id' do 17 | resources :microposts, only: [:index] 18 | end 19 | end 20 | 21 | end 22 | 23 | get '/docs/index', to: 'docs#index' 24 | 25 | end 26 | -------------------------------------------------------------------------------- /app/docs/slate/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Version 1.1 4 | 5 | *July 27th, 2014* 6 | 7 | **Fixes:** 8 | 9 | - Finally, a fix for the redcarpet upgrade bug 10 | 11 | ## Version 1.0 12 | 13 | *July 2, 2014* 14 | 15 | [View Issues](https://github.com/tripit/slate/issues?milestone=1&state=closed) 16 | 17 | **Features:** 18 | 19 | - Responsive designs for phones and tablets 20 | - Started tagging versions 21 | 22 | **Fixes:** 23 | 24 | - Fixed 'unrecognized expression' error 25 | - Fixed #undefined hash bug 26 | - Fixed bug where the current language tab would be unselected 27 | - Fixed bug where tocify wouldn't highlight the current section while searching 28 | - Fixed bug where ids of header tags would have special characters that caused problems 29 | - Updated layout so that pages with disabled search wouldn't load search.js 30 | - Cleaned up Javascript 31 | -------------------------------------------------------------------------------- /app/docs/slate/source/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: API Reference 3 | 4 | language_tabs: 5 | - ruby 6 | 7 | toc_footers: 8 | - Documentation Powered by Slate 9 | 10 | includes: 11 | - errors 12 | 13 | search: true 14 | --- 15 | 16 | # 介绍 17 | 18 | API 文档 19 | 20 | # 获取用户信息 21 | 22 | ## V1 23 | 24 | ## HTTP 请求 25 | 26 | `GET http://my-site/api/v1/users/` 27 | 28 | ## 请求参数 29 | 30 | 参数名 | 是否必需 | 描述 31 | -----| --------| ------- 32 | id | 是 | 用户 id| 33 | 34 | ## 响应 35 | 36 | ```json 37 | 38 | { 39 | "user": 40 | { 41 | "id":1, 42 | "email":"test-user-00@mail.com", 43 | "name":"test-user-00", 44 | "activated":"2015-05-02T07:47:14.697Z", 45 | "admin":false, 46 | "created_at":"2015-05-02T07:47:14.708Z", 47 | "updated_at":"2015-05-02T07:47:14.708Z" 48 | } 49 | } 50 | ``` 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /app/docs/slate/config.rb: -------------------------------------------------------------------------------- 1 | # Markdown 2 | set :markdown_engine, :redcarpet 3 | set :markdown, 4 | fenced_code_blocks: true, 5 | smartypants: true, 6 | disable_indented_code_blocks: true, 7 | prettify: true, 8 | tables: true, 9 | with_toc_data: true, 10 | no_intra_emphasis: true 11 | 12 | # Assets 13 | set :css_dir, 'stylesheets' 14 | set :js_dir, 'javascripts' 15 | set :images_dir, 'images' 16 | set :fonts_dir, 'fonts' 17 | 18 | # Activate the syntax highlighter 19 | activate :syntax 20 | 21 | # Github pages require relative links 22 | activate :relative_assets 23 | set :relative_links, true 24 | 25 | # Build Configuration 26 | set :build_dir, '../../../public/docs/' 27 | configure :build do 28 | activate :minify_css 29 | activate :minify_javascript 30 | # activate :relative_assets 31 | # activate :asset_hash 32 | # activate :gzip 33 | end 34 | -------------------------------------------------------------------------------- /app/policies/application_policy.rb: -------------------------------------------------------------------------------- 1 | class ApplicationPolicy 2 | attr_reader :user, :record 3 | 4 | def initialize(user, record) 5 | @user = user 6 | @record = record 7 | end 8 | 9 | def index? 10 | false 11 | end 12 | 13 | def show? 14 | scope.where(:id => record.id).exists? 15 | end 16 | 17 | def create? 18 | false 19 | end 20 | 21 | def new? 22 | create? 23 | end 24 | 25 | def update? 26 | false 27 | end 28 | 29 | def edit? 30 | update? 31 | end 32 | 33 | def destroy? 34 | false 35 | end 36 | 37 | def scope 38 | Pundit.policy_scope!(user, record.class) 39 | end 40 | 41 | class Scope 42 | attr_reader :user, :scope 43 | 44 | def initialize(user, scope) 45 | @user = user 46 | @scope = scope 47 | end 48 | 49 | def resolve 50 | scope 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /spec/controllers/users_controller_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'awesome_print' 4 | 5 | RSpec.describe Api::V1::UsersController, type: :controller do 6 | 7 | render_views 8 | 9 | describe "GET #show" do 10 | 11 | before do 12 | @user = User.create(email: 'test01@mail.com', password: '123123') 13 | @request.headers['Authorization'] = "Token token=#{@user.authentication_token}, email=#{@user.email}" # 问题point 14 | end 15 | 16 | after do 17 | @request.headers['Authorization'] = nil 18 | end 19 | 20 | it "returns http success" do 21 | get :show, { id: @user.to_param, format: :json } 22 | 23 | ap response.body # 此处有一个奇怪的反应,打印 "" 这个""不知从何处而来。原因是加入了@request.headers['Authorization'] = "xxx“的设置,去掉就正常返回。 24 | json_hash = JSON.parse(response.body) 25 | expect(response).to be_success 26 | end 27 | 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | users = User.create([ 10 | { 11 | email: 'test-user-00@mail.com', 12 | name: 'test-user-00', 13 | activated: DateTime.now, 14 | admin: false 15 | }, 16 | { 17 | email: 'test-user-01@mail.com', 18 | name: 'test-user-01', 19 | activated: DateTime.now, 20 | admin: false 21 | } 22 | ]) 23 | -------------------------------------------------------------------------------- /app/docs/slate/source/stylesheets/_syntax.scss.erb: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2008-2013 Concur Technologies, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | not use this file except in compliance with the License. You may obtain 6 | a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | License for the specific language governing permissions and limitations 14 | under the License. 15 | */ 16 | 17 | @import 'variables'; 18 | 19 | <%= Rouge::Themes::Base16::Monokai.render(:scope => '.highlight') %> 20 | 21 | .highlight .c, .highlight .cm, .highlight .c1, .highlight .cs { 22 | color: #909090; 23 | } 24 | 25 | .highlight, .highlight .w { 26 | background-color: $code-bg; 27 | } -------------------------------------------------------------------------------- /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: 9c271f57f1e9d5b1ce4b9e05bf34e4b5603bbf3783c9c4aa75ba127156225ac5350c44d5f522079a7ea596f6011f76fe1611112e3811614a257b762b2a957bde 15 | 16 | test: 17 | secret_key_base: 62cfee998312fa318afc156f1c20e5b1d936c9f5a9b5661c0ea9d869967d728a9d24551f18efaf32fb76a03b8373486cfefc65d0a53d759079e6c38686b2555d 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 | -------------------------------------------------------------------------------- /app/docs/slate/source/includes/_errors.md: -------------------------------------------------------------------------------- 1 | # Errors 2 | 3 | 4 | 5 | The Kittn API uses the following error codes: 6 | 7 | 8 | Error Code | Meaning 9 | ---------- | ------- 10 | 400 | Bad Request -- Your request sucks 11 | 401 | Unauthorized -- Your API key is wrong 12 | 403 | Forbidden -- The kitten requested is hidden for administrators only 13 | 404 | Not Found -- The specified kitten could not be found 14 | 405 | Method Not Allowed -- You tried to access a kitten with an invalid method 15 | 406 | Not Acceptable -- You requested a format that isn't json 16 | 410 | Gone -- The kitten requested has been removed from our servers 17 | 418 | I'm a teapot 18 | 429 | Too Many Requests -- You're requesting too many kittens! Slow down! 19 | 500 | Internal Server Error -- We had a problem with our server. Try again later. 20 | 503 | Service Unavailable -- We're temporarially offline for maintanance. Please try again later. 21 | -------------------------------------------------------------------------------- /app/docs/slate/source/stylesheets/_icon-font.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'icomoon'; 3 | src:font-url('icomoon.eot'); 4 | src:font-url('icomoon.eot?#iefix') format('embedded-opentype'), 5 | font-url('icomoon.ttf') format('truetype'), 6 | font-url('icomoon.woff') format('woff'), 7 | font-url('icomoon.svg#icomoon') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | } 11 | 12 | %icon { 13 | font-family: 'icomoon'; 14 | speak: none; 15 | font-style: normal; 16 | font-weight: normal; 17 | font-variant: normal; 18 | text-transform: none; 19 | line-height: 1; 20 | } 21 | 22 | %icon-exclamation-sign { 23 | @extend %icon; 24 | content: "\e600"; 25 | } 26 | %icon-question-sign { 27 | @extend %icon; 28 | content: "\e601"; 29 | } 30 | %icon-info-sign { 31 | @extend %icon; 32 | content: "\e602"; 33 | } 34 | %icon-remove-sign { 35 | @extend %icon; 36 | content: "\e603"; 37 | } 38 | %icon-plus-sign { 39 | @extend %icon; 40 | content: "\e604"; 41 | } 42 | %icon-minus-sign { 43 | @extend %icon; 44 | content: "\e605"; 45 | } 46 | %icon-ok-sign { 47 | @extend %icon; 48 | content: "\e606"; 49 | } 50 | %icon-search { 51 | @extend %icon; 52 | content: "\e607"; 53 | } 54 | -------------------------------------------------------------------------------- /app/docs/slate/source/javascripts/app/toc.js: -------------------------------------------------------------------------------- 1 | (function (global) { 2 | 'use strict'; 3 | 4 | var closeToc = function() { 5 | $(".tocify-wrapper").removeClass('open'); 6 | $("#nav-button").removeClass('open'); 7 | }; 8 | 9 | var makeToc = function() { 10 | global.toc = $("#toc").tocify({ 11 | selectors: 'h1, h2', 12 | extendPage: false, 13 | theme: 'none', 14 | smoothScroll: false, 15 | showEffectSpeed: 0, 16 | hideEffectSpeed: 180, 17 | ignoreSelector: '.toc-ignore', 18 | highlightOffset: 60, 19 | scrollTo: -1, 20 | scrollHistory: true, 21 | hashGenerator: function (text, element) { 22 | return element.prop('id'); 23 | } 24 | }).data('toc-tocify'); 25 | 26 | $("#nav-button").click(function() { 27 | $(".tocify-wrapper").toggleClass('open'); 28 | $("#nav-button").toggleClass('open'); 29 | return false; 30 | }); 31 | 32 | $(".page-wrapper").click(closeToc); 33 | $(".tocify-item").click(closeToc); 34 | }; 35 | 36 | // Hack to make already open sections to start opened, 37 | // instead of displaying an ugly animation 38 | function animate () { 39 | setTimeout(function() { 40 | toc.setOption('showEffectSpeed', 180); 41 | }, 50); 42 | } 43 | 44 | $(makeToc); 45 | $(animate); 46 | 47 | })(window); 48 | 49 | -------------------------------------------------------------------------------- /app/controllers/api/v1/base_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::V1::BaseController < ApplicationController 2 | 3 | respond_to :json 4 | 5 | include Pundit 6 | 7 | attr_accessor :current_user 8 | 9 | # disable the CSRF token 10 | protect_from_forgery with: :null_session 11 | 12 | # disable cookies (no set-cookies header in response) 13 | before_action :destroy_session 14 | 15 | rescue_from Pundit::NotAuthorizedError, with: :deny_access 16 | 17 | def destroy_session 18 | request.session_options[:skip] = true 19 | end 20 | 21 | def api_error(opts = {}) 22 | render nothing: true, status: opts[:status] 23 | end 24 | 25 | def authenticate_user! 26 | token, options = ActionController::HttpAuthentication::Token.token_and_options(request) 27 | 28 | user_email = options.blank?? nil : options[:email] 29 | user = user_email && User.find_by(email: user_email) 30 | 31 | if user && ActiveSupport::SecurityUtils.secure_compare(user.authentication_token, token) 32 | self.current_user = user 33 | else 34 | return unauthenticated! 35 | end 36 | end 37 | 38 | def unauthenticated! 39 | api_error(status: 401) 40 | end 41 | 42 | def deny_access 43 | api_error(status: 403) 44 | end 45 | 46 | def paginate(resource) 47 | resource = resource.page(params[:page] || 1) 48 | if params[:per_page] 49 | resource = resource.per(params[:per_page]) 50 | end 51 | 52 | return resource 53 | end 54 | 55 | 56 | end 57 | -------------------------------------------------------------------------------- /db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended that you check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(version: 20150503131743) do 15 | 16 | create_table "microposts", force: :cascade do |t| 17 | t.string "title" 18 | t.text "content" 19 | t.integer "user_id" 20 | t.datetime "created_at", null: false 21 | t.datetime "updated_at", null: false 22 | end 23 | 24 | create_table "users", force: :cascade do |t| 25 | t.string "email" 26 | t.string "name" 27 | t.datetime "activated" 28 | t.boolean "admin", default: false 29 | t.datetime "created_at", null: false 30 | t.datetime "updated_at", null: false 31 | t.string "authentication_token" 32 | t.string "password_digest" 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'rack/redis_throttle' 3 | require File.expand_path('../boot', __FILE__) 4 | 5 | require 'rails/all' 6 | 7 | # Require the gems listed in Gemfile, including any gems 8 | # you've limited to :test, :development, or :production. 9 | Bundler.require(*Rails.groups) 10 | 11 | module BuildAnApiRailsDemo 12 | class Application < Rails::Application 13 | # Settings in config/environments/* take precedence over those specified here. 14 | # Application configuration should go into files in config/initializers 15 | # -- all .rb files in that directory are automatically loaded. 16 | 17 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 18 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 19 | # config.time_zone = 'Central Time (US & Canada)' 20 | 21 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 22 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 23 | # config.i18n.default_locale = :de 24 | 25 | # Do not swallow errors in after_commit/after_rollback callbacks. 26 | config.active_record.raise_in_transactional_callbacks = true 27 | 28 | config.autoload_paths << Rails.root.join('app/policies') 29 | 30 | # 为了测试我们把 limit 设置为 3 31 | config.middleware.use Rack::RedisThrottle::Daily, max: 10000 32 | 33 | config.middleware.insert_before 0, "Rack::Cors" do 34 | allow do 35 | origins '*' 36 | resource '*', :headers => :any, :methods => [:get, :post, :put, :patch, :delete, :options, :head] 37 | end 38 | end 39 | 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /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 | end 42 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | 4 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' 5 | gem 'rails', '4.2.0' 6 | # Use sqlite3 as the database for Active Record 7 | gem 'sqlite3' 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 | 17 | # Use jquery as the JavaScript library 18 | gem 'jquery-rails' 19 | # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks 20 | gem 'turbolinks' 21 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder 22 | gem 'jbuilder', '~> 2.0' 23 | # bundle exec rake doc:rails generates the API under doc/api. 24 | gem 'sdoc', '~> 0.4.0', group: :doc 25 | 26 | # Use ActiveModel has_secure_password 27 | gem 'bcrypt', '~> 3.1.7' 28 | 29 | # Use Unicorn as the app server 30 | # gem 'unicorn' 31 | 32 | # Use Capistrano for deployment 33 | # gem 'capistrano-rails', group: :development 34 | 35 | group :development, :test do 36 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console 37 | gem 'byebug' 38 | 39 | # Access an IRB console on exception pages or by using <%= console %> in views 40 | gem 'web-console', '~> 2.0' 41 | 42 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring 43 | gem 'spring' 44 | 45 | gem 'rspec-rails' 46 | end 47 | 48 | gem 'pundit' 49 | gem 'kaminari' 50 | 51 | gem 'redis-throttle', git: 'git://github.com/andreareginato/redis-throttle.git' 52 | 53 | gem 'rack-cors' 54 | 55 | gem 'responders' 56 | 57 | gem 'awesome_print' 58 | 59 | gem 'database_cleaner' 60 | 61 | 62 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file is copied to spec/ when you run 'rails generate rspec:install' 2 | ENV["RAILS_ENV"] ||= 'test' 3 | require File.expand_path("../../config/environment", __FILE__) 4 | require 'rspec/rails' 5 | require 'rspec/autorun' 6 | 7 | # Requires supporting ruby files with custom matchers and macros, etc, 8 | # in spec/support/ and its subdirectories. 9 | Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } 10 | 11 | # Checks for pending migrations before tests are run. 12 | # If you are not using ActiveRecord, you can remove this line. 13 | ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration) 14 | 15 | RSpec.configure do |config| 16 | # ## Mock Framework 17 | # 18 | # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: 19 | # 20 | # config.mock_with :mocha 21 | # config.mock_with :flexmock 22 | # config.mock_with :rr 23 | 24 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 25 | config.fixture_path = "#{::Rails.root}/spec/fixtures" 26 | 27 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 28 | # examples within a transaction, remove the following line or assign false 29 | # instead of true. 30 | config.use_transactional_fixtures = true 31 | 32 | # If true, the base class of anonymous controllers will be inferred 33 | # automatically. This will be the default behavior in future versions of 34 | # rspec-rails. 35 | config.infer_base_class_for_anonymous_controllers = false 36 | 37 | # Run specs in random order to surface order dependencies. If you find an 38 | # order dependency and want to debug it, you can fix the order by providing 39 | # the seed, which is printed after each run. 40 | # --seed 1234 41 | config.order = "random" 42 | 43 | config.before(:suite) do 44 | DatabaseCleaner.strategy = :transaction 45 | DatabaseCleaner.clean_with(:truncation) 46 | end 47 | 48 | config.around(:each) do |example| 49 | DatabaseCleaner.cleaning do 50 | example.run 51 | end 52 | end 53 | 54 | end 55 | -------------------------------------------------------------------------------- /app/docs/slate/source/javascripts/app/search.js: -------------------------------------------------------------------------------- 1 | (function (global) { 2 | 'use strict'; 3 | 4 | var $global = $(global); 5 | var content, darkBox, searchResults; 6 | var highlightOpts = { element: 'span', className: 'search-highlight' }; 7 | 8 | var index = new lunr.Index(); 9 | 10 | index.ref('id'); 11 | index.field('title', { boost: 10 }); 12 | index.field('body'); 13 | index.pipeline.add(lunr.trimmer, lunr.stopWordFilter); 14 | 15 | $(populate); 16 | $(bind); 17 | 18 | function populate() { 19 | $('h1, h2').each(function() { 20 | var title = $(this); 21 | var body = title.nextUntil('h1, h2'); 22 | index.add({ 23 | id: title.prop('id'), 24 | title: title.text(), 25 | body: body.text() 26 | }); 27 | }); 28 | } 29 | 30 | function bind() { 31 | content = $('.content'); 32 | darkBox = $('.dark-box'); 33 | searchResults = $('.search-results'); 34 | 35 | $('#input-search').on('keyup', search); 36 | } 37 | 38 | function search(event) { 39 | unhighlight(); 40 | searchResults.addClass('visible'); 41 | 42 | // ESC clears the field 43 | if (event.keyCode === 27) this.value = ''; 44 | 45 | if (this.value) { 46 | var results = index.search(this.value).filter(function(r) { 47 | return r.score > 0.0001; 48 | }); 49 | 50 | if (results.length) { 51 | searchResults.empty(); 52 | $.each(results, function (index, result) { 53 | var elem = document.getElementById(result.ref); 54 | searchResults.append("
  • " + $(elem).text() + "
  • "); 55 | }); 56 | highlight.call(this); 57 | } else { 58 | searchResults.html('
  • '); 59 | $('.search-results li').text('No Results Found for "' + this.value + '"'); 60 | } 61 | } else { 62 | unhighlight(); 63 | searchResults.removeClass('visible'); 64 | } 65 | } 66 | 67 | function highlight() { 68 | if (this.value) content.highlight(this.value, highlightOpts); 69 | } 70 | 71 | function unhighlight() { 72 | content.unhighlight(highlightOpts); 73 | } 74 | 75 | })(window); 76 | -------------------------------------------------------------------------------- /app/docs/slate/source/javascripts/app/lang.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2008-2013 Concur Technologies, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | not use this file except in compliance with the License. You may obtain 6 | a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | License for the specific language governing permissions and limitations 14 | under the License. 15 | */ 16 | (function (global) { 17 | 'use strict'; 18 | 19 | var languages = []; 20 | 21 | global.setupLanguages = setupLanguages; 22 | global.activateLanguage = activateLanguage; 23 | 24 | function activateLanguage(language) { 25 | if (!language) return; 26 | if (language === "") return; 27 | 28 | $(".lang-selector a").removeClass('active'); 29 | $(".lang-selector a[data-language-name='" + language + "']").addClass('active'); 30 | for (var i=0; i < languages.length; i++) { 31 | $(".highlight." + languages[i]).hide(); 32 | } 33 | $(".highlight." + language).show(); 34 | 35 | global.toc.calculateHeights(); 36 | 37 | // scroll to the new location of the position 38 | if ($(window.location.hash).get(0)) { 39 | $(window.location.hash).get(0).scrollIntoView(true); 40 | } 41 | } 42 | 43 | // if a button is clicked, add the state to the history 44 | function pushURL(language) { 45 | if (!history) { return; } 46 | var hash = window.location.hash; 47 | if (hash) { 48 | hash = hash.replace(/^#+/, ''); 49 | } 50 | history.pushState({}, '', '?' + language + '#' + hash); 51 | 52 | // save language as next default 53 | localStorage.setItem("language", language); 54 | } 55 | 56 | function setupLanguages(l) { 57 | var currentLanguage = l[0]; 58 | var defaultLanguage = localStorage.getItem("language"); 59 | 60 | languages = l; 61 | 62 | if ((location.search.substr(1) !== "") && (jQuery.inArray(location.search.substr(1), languages)) != -1) { 63 | // the language is in the URL, so use that language! 64 | activateLanguage(location.search.substr(1)); 65 | 66 | localStorage.setItem("language", location.search.substr(1)); 67 | } else if ((defaultLanguage !== null) && (jQuery.inArray(defaultLanguage, languages) != -1)) { 68 | // the language was the last selected one saved in localstorage, so use that language! 69 | activateLanguage(defaultLanguage); 70 | } else { 71 | // no language selected, so use the default 72 | activateLanguage(languages[0]); 73 | } 74 | } 75 | 76 | // if we click on a language tab, activate that language 77 | $(function() { 78 | $(".lang-selector a").on("click", function() { 79 | var language = $(this).data("language-name"); 80 | pushURL(language); 81 | activateLanguage(language); 82 | return false; 83 | }); 84 | window.onpopstate = function(event) { 85 | activateLanguage(window.location.search.substr(1)); 86 | }; 87 | }); 88 | })(window); 89 | -------------------------------------------------------------------------------- /app/docs/slate/source/stylesheets/print.css.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @import 'normalize'; 3 | @import 'compass'; 4 | @import 'variables'; 5 | @import 'icon-font'; 6 | 7 | /* 8 | Copyright 2008-2013 Concur Technologies, Inc. 9 | 10 | Licensed under the Apache License, Version 2.0 (the "License"); you may 11 | not use this file except in compliance with the License. You may obtain 12 | a copy of the License at 13 | 14 | http://www.apache.org/licenses/LICENSE-2.0 15 | 16 | Unless required by applicable law or agreed to in writing, software 17 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 18 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 19 | License for the specific language governing permissions and limitations 20 | under the License. 21 | */ 22 | 23 | $print-color: #999; 24 | $print-color-light: #ccc; 25 | $print-font-size: 12px; 26 | 27 | body { 28 | @extend %default-font; 29 | } 30 | 31 | .tocify, .toc-footer, .lang-selector, .search, #nav-button { 32 | display: none; 33 | } 34 | 35 | .tocify-wrapper>img { 36 | margin: 0 auto; 37 | display: block; 38 | } 39 | 40 | .content { 41 | font-size: 12px; 42 | 43 | pre, code { 44 | @extend %code-font; 45 | @extend %break-words; 46 | border: 1px solid $print-color; 47 | border-radius: 5px; 48 | font-size: 0.8em; 49 | } 50 | 51 | pre { 52 | padding: 1.3em; 53 | } 54 | 55 | code { 56 | padding: 0.2em; 57 | } 58 | 59 | table { 60 | border: 1px solid $print-color; 61 | tr { 62 | border-bottom: 1px solid $print-color; 63 | } 64 | td,th { 65 | padding: 0.7em; 66 | } 67 | } 68 | 69 | p { 70 | line-height: 1.5; 71 | } 72 | 73 | a { 74 | text-decoration: none; 75 | color: #000; 76 | } 77 | 78 | h1 { 79 | @extend %header-font; 80 | font-size: 2.5em; 81 | padding-top: 0.5em; 82 | padding-bottom: 0.5em; 83 | margin-top: 1em; 84 | margin-bottom: $h1-margin-bottom; 85 | border: 2px solid $print-color-light; 86 | border-width: 2px 0; 87 | text-align: center; 88 | } 89 | 90 | h2 { 91 | @extend %header-font; 92 | font-size: 1.8em; 93 | margin-top: 2em; 94 | border-top: 2px solid $print-color-light; 95 | padding-top: 0.8em; 96 | } 97 | 98 | h1+h2, h1+div+h2 { 99 | border-top: none; 100 | padding-top: 0; 101 | margin-top: 0; 102 | } 103 | 104 | h3, h4 { 105 | @extend %header-font; 106 | font-size: 0.8em; 107 | margin-top: 1.5em; 108 | margin-bottom: 0.8em; 109 | text-transform: uppercase; 110 | } 111 | 112 | h5, h6 { 113 | text-transform: uppercase; 114 | } 115 | 116 | aside { 117 | padding: 1em; 118 | border: 1px solid $print-color-light; 119 | border-radius: 5px; 120 | margin-top: 1.5em; 121 | margin-bottom: 1.5em; 122 | line-height: 1.6; 123 | } 124 | 125 | aside:before { 126 | vertical-align: middle; 127 | padding-right: 0.5em; 128 | font-size: 14px; 129 | } 130 | 131 | aside.notice:before { 132 | @extend %icon-info-sign; 133 | } 134 | 135 | aside.warning:before { 136 | @extend %icon-exclamation-sign; 137 | } 138 | 139 | aside.success:before { 140 | @extend %icon-ok-sign; 141 | } 142 | } -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both threaded web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application 18 | # Add `rack-cache` to your Gemfile before enabling this. 19 | # For large-scale production use, consider using a caching reverse proxy like 20 | # NGINX, varnish or squid. 21 | # config.action_dispatch.rack_cache = true 22 | 23 | # Disable serving static files from the `/public` folder by default since 24 | # Apache or NGINX already handles this. 25 | config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present? 26 | 27 | # Compress JavaScripts and CSS. 28 | config.assets.js_compressor = :uglifier 29 | # config.assets.css_compressor = :sass 30 | 31 | # Do not fallback to assets pipeline if a precompiled asset is missed. 32 | config.assets.compile = false 33 | 34 | # Asset digests allow you to set far-future HTTP expiration dates on all assets, 35 | # yet still be able to expire them through the digest params. 36 | config.assets.digest = true 37 | 38 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb 39 | 40 | # Specifies the header that your server uses for sending files. 41 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 42 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 43 | 44 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 45 | # config.force_ssl = true 46 | 47 | # Use the lowest log level to ensure availability of diagnostic information 48 | # when problems arise. 49 | config.log_level = :debug 50 | 51 | # Prepend all log lines with the following tags. 52 | # config.log_tags = [ :subdomain, :uuid ] 53 | 54 | # Use a different logger for distributed setups. 55 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 56 | 57 | # Use a different cache store in production. 58 | # config.cache_store = :mem_cache_store 59 | 60 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 61 | # config.action_controller.asset_host = 'http://assets.example.com' 62 | 63 | # Ignore bad email addresses and do not raise email delivery errors. 64 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 65 | # config.action_mailer.raise_delivery_errors = false 66 | 67 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 68 | # the I18n.default_locale when a translation cannot be found). 69 | config.i18n.fallbacks = true 70 | 71 | # Send deprecation notices to registered listeners. 72 | config.active_support.deprecation = :notify 73 | 74 | # Use default logging formatter so that PID and timestamp are not suppressed. 75 | config.log_formatter = ::Logger::Formatter.new 76 | 77 | # Do not dump schema after migrations. 78 | config.active_record.dump_schema_after_migration = false 79 | end 80 | -------------------------------------------------------------------------------- /app/docs/slate/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | activesupport (4.1.10) 5 | i18n (~> 0.6, >= 0.6.9) 6 | json (~> 1.7, >= 1.7.7) 7 | minitest (~> 5.1) 8 | thread_safe (~> 0.1) 9 | tzinfo (~> 1.1) 10 | celluloid (0.16.0) 11 | timers (~> 4.0.0) 12 | chunky_png (1.3.4) 13 | coffee-script (2.4.1) 14 | coffee-script-source 15 | execjs 16 | coffee-script-source (1.9.1.1) 17 | compass (1.0.3) 18 | chunky_png (~> 1.2) 19 | compass-core (~> 1.0.2) 20 | compass-import-once (~> 1.0.5) 21 | rb-fsevent (>= 0.9.3) 22 | rb-inotify (>= 0.9) 23 | sass (>= 3.3.13, < 3.5) 24 | compass-core (1.0.3) 25 | multi_json (~> 1.0) 26 | sass (>= 3.3.0, < 3.5) 27 | compass-import-once (1.0.5) 28 | sass (>= 3.2, < 3.5) 29 | erubis (2.7.0) 30 | execjs (2.5.2) 31 | ffi (1.9.8) 32 | haml (4.0.6) 33 | tilt 34 | hike (1.2.3) 35 | hitimes (1.2.2) 36 | hooks (0.4.0) 37 | uber (~> 0.0.4) 38 | i18n (0.7.0) 39 | json (1.8.2) 40 | kramdown (1.7.0) 41 | libv8 (3.16.14.7) 42 | listen (2.10.0) 43 | celluloid (~> 0.16.0) 44 | rb-fsevent (>= 0.9.3) 45 | rb-inotify (>= 0.9) 46 | middleman (3.3.11) 47 | coffee-script (~> 2.2) 48 | compass (>= 1.0.0, < 2.0.0) 49 | compass-import-once (= 1.0.5) 50 | execjs (~> 2.0) 51 | haml (>= 4.0.5) 52 | kramdown (~> 1.2) 53 | middleman-core (= 3.3.11) 54 | middleman-sprockets (>= 3.1.2) 55 | sass (>= 3.4.0, < 4.0) 56 | uglifier (~> 2.5) 57 | middleman-core (3.3.11) 58 | activesupport (~> 4.1.0) 59 | bundler (~> 1.1) 60 | erubis 61 | hooks (~> 0.3) 62 | i18n (~> 0.7.0) 63 | listen (>= 2.7.9, < 3.0) 64 | padrino-helpers (~> 0.12.3) 65 | rack (>= 1.4.5, < 2.0) 66 | rack-test (~> 0.6.2) 67 | thor (>= 0.15.2, < 2.0) 68 | tilt (~> 1.4.1, < 2.0) 69 | middleman-gh-pages (0.0.3) 70 | rake (> 0.9.3) 71 | middleman-sprockets (3.4.2) 72 | middleman-core (>= 3.3) 73 | sprockets (~> 2.12.1) 74 | sprockets-helpers (~> 1.1.0) 75 | sprockets-sass (~> 1.3.0) 76 | middleman-syntax (2.0.0) 77 | middleman-core (~> 3.2) 78 | rouge (~> 1.0) 79 | minitest (5.6.1) 80 | multi_json (1.11.0) 81 | padrino-helpers (0.12.5) 82 | i18n (~> 0.6, >= 0.6.7) 83 | padrino-support (= 0.12.5) 84 | tilt (~> 1.4.1) 85 | padrino-support (0.12.5) 86 | activesupport (>= 3.1) 87 | rack (1.6.0) 88 | rack-test (0.6.3) 89 | rack (>= 1.0) 90 | rake (10.4.2) 91 | rb-fsevent (0.9.4) 92 | rb-inotify (0.9.5) 93 | ffi (>= 0.5.0) 94 | redcarpet (3.2.3) 95 | ref (1.0.5) 96 | rouge (1.8.0) 97 | sass (3.4.13) 98 | sprockets (2.12.3) 99 | hike (~> 1.2) 100 | multi_json (~> 1.0) 101 | rack (~> 1.0) 102 | tilt (~> 1.1, != 1.3.0) 103 | sprockets-helpers (1.1.0) 104 | sprockets (~> 2.0) 105 | sprockets-sass (1.3.1) 106 | sprockets (~> 2.0) 107 | tilt (~> 1.1) 108 | therubyracer (0.12.2) 109 | libv8 (~> 3.16.14.0) 110 | ref 111 | thor (0.19.1) 112 | thread_safe (0.3.5) 113 | tilt (1.4.1) 114 | timers (4.0.1) 115 | hitimes 116 | tzinfo (1.2.2) 117 | thread_safe (~> 0.1) 118 | uber (0.0.13) 119 | uglifier (2.7.1) 120 | execjs (>= 0.3.0) 121 | json (>= 1.8.0) 122 | 123 | PLATFORMS 124 | ruby 125 | 126 | DEPENDENCIES 127 | middleman (~> 3.3.10) 128 | middleman-gh-pages (~> 0.0.3) 129 | middleman-syntax (~> 2.0.0) 130 | rake (~> 10.4.2) 131 | redcarpet (~> 3.2.2) 132 | rouge (~> 1.8.0) 133 | therubyracer (~> 0.12.1) 134 | -------------------------------------------------------------------------------- /app/docs/slate/source/layouts/layout.erb: -------------------------------------------------------------------------------- 1 | <%# 2 | Copyright 2008-2013 Concur Technologies, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | not use this file except in compliance with the License. You may obtain 6 | a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | License for the specific language governing permissions and limitations 14 | under the License. 15 | %> 16 | <% language_tabs = current_page.data.language_tabs %> 17 | 18 | 19 | 20 | 21 | 22 | 23 | <%= current_page.data.title || "API Documentation" %> 24 | 25 | <%= stylesheet_link_tag :screen, media: :screen %> 26 | <%= stylesheet_link_tag :print, media: :print %> 27 | 28 | <% if current_page.data.search %> 29 | <%= javascript_include_tag "all" %> 30 | <% else %> 31 | <%= javascript_include_tag "all_nosearch" %> 32 | <% end %> 33 | 34 | <% if language_tabs %> 35 | 40 | <% end %> 41 | 42 | 43 | 44 | 45 | 46 | NAV 47 | <%= image_tag('navbar.png') %> 48 | 49 | 50 |
    51 | <%= image_tag "logo.png" %> 52 | <% if language_tabs %> 53 |
    54 | <% language_tabs.each do |lang| %> 55 | <% if lang.is_a? Hash %> 56 | <%= lang.values.first %> 57 | <% else %> 58 | <%= lang %> 59 | <% end %> 60 | <% end %> 61 |
    62 | <% end %> 63 | <% if current_page.data.search %> 64 | 67 | 68 | <% end %> 69 |
    70 |
    71 | <% if current_page.data.toc_footers %> 72 | 77 | <% end %> 78 |
    79 |
    80 |
    81 |
    82 | <%= yield %> 83 | <% current_page.data.includes && current_page.data.includes.each do |include| %> 84 | <%= partial "includes/#{include}" %> 85 | <% end %> 86 |
    87 |
    88 | <% if language_tabs %> 89 |
    90 | <% language_tabs.each do |lang| %> 91 | <% if lang.is_a? Hash %> 92 | <%= lang.values.first %> 93 | <% else %> 94 | <%= lang %> 95 | <% end %> 96 | <% end %> 97 |
    98 | <% end %> 99 |
    100 |
    101 | 102 | 103 | -------------------------------------------------------------------------------- /app/docs/slate/source/stylesheets/_variables.scss: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2008-2013 Concur Technologies, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | not use this file except in compliance with the License. You may obtain 6 | a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | License for the specific language governing permissions and limitations 14 | under the License. 15 | */ 16 | 17 | 18 | //////////////////////////////////////////////////////////////////////////////// 19 | // CUSTOMIZE SLATE 20 | //////////////////////////////////////////////////////////////////////////////// 21 | // Use these settings to help adjust the appearance of Slate 22 | 23 | 24 | // BACKGROUND COLORS 25 | //////////////////// 26 | $nav-bg: #393939; 27 | $examples-bg: #393939; 28 | $code-bg: #292929; 29 | $code-annotation-bg: #1c1c1c; 30 | $nav-subitem-bg: #262626; 31 | $nav-active-bg: #2467af; 32 | $lang-select-border: #000; 33 | $lang-select-bg: #222; 34 | $lang-select-active-bg: $examples-bg; // feel free to change this to blue or something 35 | $lang-select-pressed-bg: #111; // color of language tab bg when mouse is pressed 36 | $main-bg: #eaf2f6; 37 | $aside-notice-bg: #8fbcd4; 38 | $aside-warning-bg: #c97a7e; 39 | $aside-success-bg: #6ac174; 40 | $search-notice-bg: #c97a7e; 41 | 42 | 43 | // TEXT COLORS 44 | //////////////////// 45 | $main-text: #333; // main content text color 46 | $nav-text: #fff; 47 | $nav-active-text: #fff; 48 | $lang-select-text: #fff; // color of unselected language tab text 49 | $lang-select-active-text: #fff; // color of selected language tab text 50 | $lang-select-pressed-text: #fff; // color of language tab text when mouse is pressed 51 | 52 | 53 | // SIZES 54 | //////////////////// 55 | $nav-width: 230px; // width of the navbar 56 | $examples-width: 50%; // portion of the screen taken up by code examples 57 | $logo-margin: 20px; // margin between nav items and logo, ignored if search is active 58 | $main-padding: 28px; // padding to left and right of content & examples 59 | $nav-padding: 15px; // padding to left and right of navbar 60 | $nav-v-padding: 10px; // padding used vertically around search boxes and results 61 | $nav-indent: 10px; // extra padding for ToC subitems 62 | $code-annotation-padding: 13px; // padding inside code annotations 63 | $h1-margin-bottom: 21px; // padding under the largest header tags 64 | $tablet-width: 930px; // min width before reverting to tablet size 65 | $phone-width: $tablet-width - $nav-width; // min width before reverting to mobile size 66 | 67 | 68 | // FONTS 69 | //////////////////// 70 | %default-font { 71 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 72 | font-size: 13px; 73 | } 74 | 75 | %header-font { 76 | @extend %default-font; 77 | font-weight: bold; 78 | } 79 | 80 | %code-font { 81 | font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, serif; 82 | font-size: 12px; 83 | line-height: 1.5; 84 | } 85 | 86 | 87 | // OTHER 88 | //////////////////// 89 | $nav-active-shadow: #000; 90 | $nav-footer-border-color: #666; 91 | $nav-embossed-border-top: #000; 92 | $nav-embossed-border-bottom: #939393; 93 | $main-embossed-text-shadow: 0px 1px 0px #fff; 94 | $search-box-border-color: #666; 95 | 96 | 97 | //////////////////////////////////////////////////////////////////////////////// 98 | // INTERNAL 99 | //////////////////////////////////////////////////////////////////////////////// 100 | // These settings are probably best left alone. 101 | 102 | %break-words { 103 | -ms-word-break: break-all; 104 | word-break: break-all; 105 | 106 | /* Non standard for webkit */ 107 | word-break: break-word; 108 | 109 | -webkit-hyphens: auto; 110 | -moz-hyphens: auto; 111 | hyphens: auto; 112 | } 113 | -------------------------------------------------------------------------------- /app/docs/slate/source/javascripts/lib/jquery.highlight.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Highlight plugin 3 | * 4 | * Based on highlight v3 by Johann Burkard 5 | * http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html 6 | * 7 | * Code a little bit refactored and cleaned (in my humble opinion). 8 | * Most important changes: 9 | * - has an option to highlight only entire words (wordsOnly - false by default), 10 | * - has an option to be case sensitive (caseSensitive - false by default) 11 | * - highlight element tag and class names can be specified in options 12 | * 13 | * Usage: 14 | * // wrap every occurrance of text 'lorem' in content 15 | * // with (default options) 16 | * $('#content').highlight('lorem'); 17 | * 18 | * // search for and highlight more terms at once 19 | * // so you can save some time on traversing DOM 20 | * $('#content').highlight(['lorem', 'ipsum']); 21 | * $('#content').highlight('lorem ipsum'); 22 | * 23 | * // search only for entire word 'lorem' 24 | * $('#content').highlight('lorem', { wordsOnly: true }); 25 | * 26 | * // don't ignore case during search of term 'lorem' 27 | * $('#content').highlight('lorem', { caseSensitive: true }); 28 | * 29 | * // wrap every occurrance of term 'ipsum' in content 30 | * // with 31 | * $('#content').highlight('ipsum', { element: 'em', className: 'important' }); 32 | * 33 | * // remove default highlight 34 | * $('#content').unhighlight(); 35 | * 36 | * // remove custom highlight 37 | * $('#content').unhighlight({ element: 'em', className: 'important' }); 38 | * 39 | * 40 | * Copyright (c) 2009 Bartek Szopka 41 | * 42 | * Licensed under MIT license. 43 | * 44 | */ 45 | 46 | jQuery.extend({ 47 | highlight: function (node, re, nodeName, className) { 48 | if (node.nodeType === 3) { 49 | var match = node.data.match(re); 50 | if (match) { 51 | var highlight = document.createElement(nodeName || 'span'); 52 | highlight.className = className || 'highlight'; 53 | var wordNode = node.splitText(match.index); 54 | wordNode.splitText(match[0].length); 55 | var wordClone = wordNode.cloneNode(true); 56 | highlight.appendChild(wordClone); 57 | wordNode.parentNode.replaceChild(highlight, wordNode); 58 | return 1; //skip added node in parent 59 | } 60 | } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children 61 | !/(script|style)/i.test(node.tagName) && // ignore script and style nodes 62 | !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted 63 | for (var i = 0; i < node.childNodes.length; i++) { 64 | i += jQuery.highlight(node.childNodes[i], re, nodeName, className); 65 | } 66 | } 67 | return 0; 68 | } 69 | }); 70 | 71 | jQuery.fn.unhighlight = function (options) { 72 | var settings = { className: 'highlight', element: 'span' }; 73 | jQuery.extend(settings, options); 74 | 75 | return this.find(settings.element + "." + settings.className).each(function () { 76 | var parent = this.parentNode; 77 | parent.replaceChild(this.firstChild, this); 78 | parent.normalize(); 79 | }).end(); 80 | }; 81 | 82 | jQuery.fn.highlight = function (words, options) { 83 | var settings = { className: 'highlight', element: 'span', caseSensitive: false, wordsOnly: false }; 84 | jQuery.extend(settings, options); 85 | 86 | if (words.constructor === String) { 87 | words = [words]; 88 | } 89 | words = jQuery.grep(words, function(word, i){ 90 | return word != ''; 91 | }); 92 | words = jQuery.map(words, function(word, i) { 93 | return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 94 | }); 95 | if (words.length == 0) { return this; }; 96 | 97 | var flag = settings.caseSensitive ? "" : "i"; 98 | var pattern = "(" + words.join("|") + ")"; 99 | if (settings.wordsOnly) { 100 | pattern = "\\b" + pattern + "\\b"; 101 | } 102 | var re = new RegExp(pattern, flag); 103 | 104 | return this.each(function () { 105 | jQuery.highlight(this, re, settings.element, settings.className); 106 | }); 107 | }; 108 | 109 | -------------------------------------------------------------------------------- /app/docs/slate/source/fonts/icomoon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/views/docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | API Reference 8 | 9 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 21 | 22 | 23 | 24 | NAV 25 | 26 | 27 | 28 |
    29 | 30 |
    31 | ruby 32 |
    33 | 36 |
      37 |
      38 |
      39 | 42 |
      43 |
      44 |
      45 |
      46 |

      介绍

      47 | 48 |

      API 文档

      49 | 50 |

      获取用户信息

      51 | 52 |

      V1

      53 | 54 |

      HTTP 请求

      55 | 56 |

      GET http://my-site/api/v1/users/<id>

      57 | 58 |

      请求参数

      59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 |
      参数名是否必需描述
      id用户 id
      73 | 74 |

      响应

      75 |
      
       76 | {
       77 |   "user":
       78 |   {
       79 |     "id":1,
       80 |     "email":"test-user-00@mail.com",
       81 |     "name":"test-user-00",
       82 |     "activated":"2015-05-02T07:47:14.697Z",
       83 |     "admin":false,
       84 |     "created_at":"2015-05-02T07:47:14.708Z",
       85 |     "updated_at":"2015-05-02T07:47:14.708Z"
       86 |    }
       87 | }
       88 | 
      89 | 90 |

      Errors

      91 | 92 | 93 | 94 |

      The Kittn API uses the following error codes:

      95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 |
      Error CodeMeaning
      400Bad Request – Your request sucks
      401Unauthorized – Your API key is wrong
      403Forbidden – The kitten requested is hidden for administrators only
      404Not Found – The specified kitten could not be found
      405Method Not Allowed – You tried to access a kitten with an invalid method
      406Not Acceptable – You requested a format that isn’t json
      410Gone – The kitten requested has been removed from our servers
      418I’m a teapot
      429Too Many Requests – You’re requesting too many kittens! Slow down!
      500Internal Server Error – We had a problem with our server. Try again later.
      503Service Unavailable – We’re temporarially offline for maintanance. Please try again later.
      147 | 148 |
      149 |
      150 |
      151 | ruby 152 |
      153 |
      154 |
      155 | 156 | 157 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GIT 2 | remote: git://github.com/andreareginato/redis-throttle.git 3 | revision: 98cf0bf5f2c3955408f2b5667c7b6ddcd459b6d4 4 | specs: 5 | redis-throttle (0.0.1) 6 | activesupport 7 | hiredis 8 | rack 9 | rack-throttle 10 | redis 11 | redis-namespace 12 | 13 | GEM 14 | remote: https://rubygems.org/ 15 | specs: 16 | actionmailer (4.2.0) 17 | actionpack (= 4.2.0) 18 | actionview (= 4.2.0) 19 | activejob (= 4.2.0) 20 | mail (~> 2.5, >= 2.5.4) 21 | rails-dom-testing (~> 1.0, >= 1.0.5) 22 | actionpack (4.2.0) 23 | actionview (= 4.2.0) 24 | activesupport (= 4.2.0) 25 | rack (~> 1.6.0) 26 | rack-test (~> 0.6.2) 27 | rails-dom-testing (~> 1.0, >= 1.0.5) 28 | rails-html-sanitizer (~> 1.0, >= 1.0.1) 29 | actionview (4.2.0) 30 | activesupport (= 4.2.0) 31 | builder (~> 3.1) 32 | erubis (~> 2.7.0) 33 | rails-dom-testing (~> 1.0, >= 1.0.5) 34 | rails-html-sanitizer (~> 1.0, >= 1.0.1) 35 | activejob (4.2.0) 36 | activesupport (= 4.2.0) 37 | globalid (>= 0.3.0) 38 | activemodel (4.2.0) 39 | activesupport (= 4.2.0) 40 | builder (~> 3.1) 41 | activerecord (4.2.0) 42 | activemodel (= 4.2.0) 43 | activesupport (= 4.2.0) 44 | arel (~> 6.0) 45 | activesupport (4.2.0) 46 | i18n (~> 0.7) 47 | json (~> 1.7, >= 1.7.7) 48 | minitest (~> 5.1) 49 | thread_safe (~> 0.3, >= 0.3.4) 50 | tzinfo (~> 1.1) 51 | arel (6.0.0) 52 | awesome_print (1.2.0) 53 | bcrypt (3.1.10) 54 | binding_of_caller (0.7.2) 55 | debug_inspector (>= 0.0.1) 56 | builder (3.2.2) 57 | byebug (4.0.5) 58 | columnize (= 0.9.0) 59 | coffee-rails (4.1.0) 60 | coffee-script (>= 2.2.0) 61 | railties (>= 4.0.0, < 5.0) 62 | coffee-script (2.4.1) 63 | coffee-script-source 64 | execjs 65 | coffee-script-source (1.9.1.1) 66 | columnize (0.9.0) 67 | database_cleaner (1.3.0) 68 | debug_inspector (0.0.2) 69 | diff-lcs (1.2.5) 70 | erubis (2.7.0) 71 | execjs (2.5.2) 72 | globalid (0.3.5) 73 | activesupport (>= 4.1.0) 74 | hiredis (0.6.0) 75 | i18n (0.7.0) 76 | jbuilder (2.2.13) 77 | activesupport (>= 3.0.0, < 5) 78 | multi_json (~> 1.2) 79 | jquery-rails (4.0.3) 80 | rails-dom-testing (~> 1.0) 81 | railties (>= 4.2.0) 82 | thor (>= 0.14, < 2.0) 83 | json (1.8.2) 84 | kaminari (0.16.3) 85 | actionpack (>= 3.0.0) 86 | activesupport (>= 3.0.0) 87 | loofah (2.0.1) 88 | nokogiri (>= 1.5.9) 89 | mail (2.6.3) 90 | mime-types (>= 1.16, < 3) 91 | mime-types (2.5) 92 | mini_portile (0.6.2) 93 | minitest (5.6.0) 94 | multi_json (1.11.0) 95 | nokogiri (1.6.6.2) 96 | mini_portile (~> 0.6.0) 97 | pundit (1.0.0) 98 | activesupport (>= 3.0.0) 99 | rack (1.6.0) 100 | rack-cors (0.4.0) 101 | rack-test (0.6.3) 102 | rack (>= 1.0) 103 | rack-throttle (0.4.0) 104 | rack (>= 1.0.0) 105 | rails (4.2.0) 106 | actionmailer (= 4.2.0) 107 | actionpack (= 4.2.0) 108 | actionview (= 4.2.0) 109 | activejob (= 4.2.0) 110 | activemodel (= 4.2.0) 111 | activerecord (= 4.2.0) 112 | activesupport (= 4.2.0) 113 | bundler (>= 1.3.0, < 2.0) 114 | railties (= 4.2.0) 115 | sprockets-rails 116 | rails-deprecated_sanitizer (1.0.3) 117 | activesupport (>= 4.2.0.alpha) 118 | rails-dom-testing (1.0.6) 119 | activesupport (>= 4.2.0.beta, < 5.0) 120 | nokogiri (~> 1.6.0) 121 | rails-deprecated_sanitizer (>= 1.0.1) 122 | rails-html-sanitizer (1.0.2) 123 | loofah (~> 2.0) 124 | railties (4.2.0) 125 | actionpack (= 4.2.0) 126 | activesupport (= 4.2.0) 127 | rake (>= 0.8.7) 128 | thor (>= 0.18.1, < 2.0) 129 | rake (10.4.2) 130 | rdoc (4.2.0) 131 | json (~> 1.4) 132 | redis (3.2.1) 133 | redis-namespace (1.5.2) 134 | redis (~> 3.0, >= 3.0.4) 135 | responders (2.1.0) 136 | railties (>= 4.2.0, < 5) 137 | rspec-core (2.14.7) 138 | rspec-expectations (2.14.5) 139 | diff-lcs (>= 1.1.3, < 2.0) 140 | rspec-mocks (2.14.5) 141 | rspec-rails (2.14.1) 142 | actionpack (>= 3.0) 143 | activemodel (>= 3.0) 144 | activesupport (>= 3.0) 145 | railties (>= 3.0) 146 | rspec-core (~> 2.14.0) 147 | rspec-expectations (~> 2.14.0) 148 | rspec-mocks (~> 2.14.0) 149 | sass (3.4.13) 150 | sass-rails (5.0.3) 151 | railties (>= 4.0.0, < 5.0) 152 | sass (~> 3.1) 153 | sprockets (>= 2.8, < 4.0) 154 | sprockets-rails (>= 2.0, < 4.0) 155 | tilt (~> 1.1) 156 | sdoc (0.4.1) 157 | json (~> 1.7, >= 1.7.7) 158 | rdoc (~> 4.0) 159 | spring (1.3.4) 160 | sprockets (3.0.2) 161 | rack (~> 1.0) 162 | sprockets-rails (2.2.4) 163 | actionpack (>= 3.0) 164 | activesupport (>= 3.0) 165 | sprockets (>= 2.8, < 4.0) 166 | sqlite3 (1.3.10) 167 | thor (0.19.1) 168 | thread_safe (0.3.5) 169 | tilt (1.4.1) 170 | turbolinks (2.5.3) 171 | coffee-rails 172 | tzinfo (1.2.2) 173 | thread_safe (~> 0.1) 174 | uglifier (2.7.1) 175 | execjs (>= 0.3.0) 176 | json (>= 1.8.0) 177 | web-console (2.1.2) 178 | activemodel (>= 4.0) 179 | binding_of_caller (>= 0.7.2) 180 | railties (>= 4.0) 181 | sprockets-rails (>= 2.0, < 4.0) 182 | 183 | PLATFORMS 184 | ruby 185 | 186 | DEPENDENCIES 187 | awesome_print 188 | bcrypt (~> 3.1.7) 189 | byebug 190 | coffee-rails (~> 4.1.0) 191 | database_cleaner 192 | jbuilder (~> 2.0) 193 | jquery-rails 194 | kaminari 195 | pundit 196 | rack-cors 197 | rails (= 4.2.0) 198 | redis-throttle! 199 | responders 200 | rspec-rails 201 | sass-rails (~> 5.0) 202 | sdoc (~> 0.4.0) 203 | spring 204 | sqlite3 205 | turbolinks 206 | uglifier (>= 1.3.0) 207 | web-console (~> 2.0) 208 | -------------------------------------------------------------------------------- /app/docs/slate/source/javascripts/lib/energize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * energize.js v0.1.0 3 | * 4 | * Speeds up click events on mobile devices. 5 | * https://github.com/davidcalhoun/energize.js 6 | */ 7 | 8 | (function() { // Sandbox 9 | /** 10 | * Don't add to non-touch devices, which don't need to be sped up 11 | */ 12 | if(!('ontouchstart' in window)) return; 13 | 14 | var lastClick = {}, 15 | isThresholdReached, touchstart, touchmove, touchend, 16 | click, closest; 17 | 18 | /** 19 | * isThresholdReached 20 | * 21 | * Compare touchstart with touchend xy coordinates, 22 | * and only fire simulated click event if the coordinates 23 | * are nearby. (don't want clicking to be confused with a swipe) 24 | */ 25 | isThresholdReached = function(startXY, xy) { 26 | return Math.abs(startXY[0] - xy[0]) > 5 || Math.abs(startXY[1] - xy[1]) > 5; 27 | }; 28 | 29 | /** 30 | * touchstart 31 | * 32 | * Save xy coordinates when the user starts touching the screen 33 | */ 34 | touchstart = function(e) { 35 | this.startXY = [e.touches[0].clientX, e.touches[0].clientY]; 36 | this.threshold = false; 37 | }; 38 | 39 | /** 40 | * touchmove 41 | * 42 | * Check if the user is scrolling past the threshold. 43 | * Have to check here because touchend will not always fire 44 | * on some tested devices (Kindle Fire?) 45 | */ 46 | touchmove = function(e) { 47 | // NOOP if the threshold has already been reached 48 | if(this.threshold) return false; 49 | 50 | this.threshold = isThresholdReached(this.startXY, [e.touches[0].clientX, e.touches[0].clientY]); 51 | }; 52 | 53 | /** 54 | * touchend 55 | * 56 | * If the user didn't scroll past the threshold between 57 | * touchstart and touchend, fire a simulated click. 58 | * 59 | * (This will fire before a native click) 60 | */ 61 | touchend = function(e) { 62 | // Don't fire a click if the user scrolled past the threshold 63 | if(this.threshold || isThresholdReached(this.startXY, [e.changedTouches[0].clientX, e.changedTouches[0].clientY])) { 64 | return; 65 | } 66 | 67 | /** 68 | * Create and fire a click event on the target element 69 | * https://developer.mozilla.org/en/DOM/event.initMouseEvent 70 | */ 71 | var touch = e.changedTouches[0], 72 | evt = document.createEvent('MouseEvents'); 73 | evt.initMouseEvent('click', true, true, window, 0, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null); 74 | evt.simulated = true; // distinguish from a normal (nonsimulated) click 75 | e.target.dispatchEvent(evt); 76 | }; 77 | 78 | /** 79 | * click 80 | * 81 | * Because we've already fired a click event in touchend, 82 | * we need to listed for all native click events here 83 | * and suppress them as necessary. 84 | */ 85 | click = function(e) { 86 | /** 87 | * Prevent ghost clicks by only allowing clicks we created 88 | * in the click event we fired (look for e.simulated) 89 | */ 90 | var time = Date.now(), 91 | timeDiff = time - lastClick.time, 92 | x = e.clientX, 93 | y = e.clientY, 94 | xyDiff = [Math.abs(lastClick.x - x), Math.abs(lastClick.y - y)], 95 | target = closest(e.target, 'A') || e.target, // needed for standalone apps 96 | nodeName = target.nodeName, 97 | isLink = nodeName === 'A', 98 | standAlone = window.navigator.standalone && isLink && e.target.getAttribute("href"); 99 | 100 | lastClick.time = time; 101 | lastClick.x = x; 102 | lastClick.y = y; 103 | 104 | /** 105 | * Unfortunately Android sometimes fires click events without touch events (seen on Kindle Fire), 106 | * so we have to add more logic to determine the time of the last click. Not perfect... 107 | * 108 | * Older, simpler check: if((!e.simulated) || standAlone) 109 | */ 110 | if((!e.simulated && (timeDiff < 500 || (timeDiff < 1500 && xyDiff[0] < 50 && xyDiff[1] < 50))) || standAlone) { 111 | e.preventDefault(); 112 | e.stopPropagation(); 113 | if(!standAlone) return false; 114 | } 115 | 116 | /** 117 | * Special logic for standalone web apps 118 | * See http://stackoverflow.com/questions/2898740/iphone-safari-web-app-opens-links-in-new-window 119 | */ 120 | if(standAlone) { 121 | window.location = target.getAttribute("href"); 122 | } 123 | 124 | /** 125 | * Add an energize-focus class to the targeted link (mimics :focus behavior) 126 | * TODO: test and/or remove? Does this work? 127 | */ 128 | if(!target || !target.classList) return; 129 | target.classList.add("energize-focus"); 130 | window.setTimeout(function(){ 131 | target.classList.remove("energize-focus"); 132 | }, 150); 133 | }; 134 | 135 | /** 136 | * closest 137 | * @param {HTMLElement} node current node to start searching from. 138 | * @param {string} tagName the (uppercase) name of the tag you're looking for. 139 | * 140 | * Find the closest ancestor tag of a given node. 141 | * 142 | * Starts at node and goes up the DOM tree looking for a 143 | * matching nodeName, continuing until hitting document.body 144 | */ 145 | closest = function(node, tagName){ 146 | var curNode = node; 147 | 148 | while(curNode !== document.body) { // go up the dom until we find the tag we're after 149 | if(!curNode || curNode.nodeName === tagName) { return curNode; } // found 150 | curNode = curNode.parentNode; // not found, so keep going up 151 | } 152 | 153 | return null; // not found 154 | }; 155 | 156 | /** 157 | * Add all delegated event listeners 158 | * 159 | * All the events we care about bubble up to document, 160 | * so we can take advantage of event delegation. 161 | * 162 | * Note: no need to wait for DOMContentLoaded here 163 | */ 164 | document.addEventListener('touchstart', touchstart, false); 165 | document.addEventListener('touchmove', touchmove, false); 166 | document.addEventListener('touchend', touchend, false); 167 | document.addEventListener('click', click, true); // TODO: why does this use capture? 168 | 169 | })(); -------------------------------------------------------------------------------- /app/docs/slate/README.md: -------------------------------------------------------------------------------- 1 | Slate 2 | ======== 3 | 4 | [![Build Status](https://travis-ci.org/tripit/slate.svg?branch=master)](https://travis-ci.org/tripit/slate) [![Dependency Status](https://gemnasium.com/tripit/slate.png)](https://gemnasium.com/tripit/slate) 5 | 6 | Slate helps you create beautiful API documentation. Think of it as an intelligent, responsive documentation template for your API. 7 | 8 | Screenshot of Example Documentation created with Slate 9 | 10 | *The example above was created with Slate. Check it out at [tripit.github.io/slate](http://tripit.github.io/slate).* 11 | 12 | Features 13 | ------------ 14 | 15 | * **Clean, intuitive design** — with Slate, the description of your API is on the left side of your documentation, and all the code examples are on the right side. Inspired by [Stripe's](https://stripe.com/docs/api) and [Paypal's](https://developer.paypal.com/webapps/developer/docs/api/) API docs. Slate is responsive, so it looks great on tablets, phones, and even print. 16 | 17 | * **Everything on a single page** — gone are the days where your users had to search through a million pages to find what they wanted. Slate puts the entire documentation on a single page. We haven't sacrificed linkability, though. As you scroll, your browser's hash will update to the nearest header, so linking to a particular point in the documentation is still natural and easy. 18 | 19 | * **Slate is just Markdown** — when you write docs with Slate, you're just writing Markdown, which makes it simple to edit and understand. Everything is written in Markdown — even the code samples are just Markdown code blocks! 20 | 21 | * **Write code samples in multiple languages** — if your API has bindings in multiple programming languages, you easily put in tabs to switch between them. In your document, you'll distinguish different languages by specifying the language name at the top of each code block, just like with Github Flavored Markdown! 22 | 23 | * **Out-of-the-box syntax highlighting** for [almost 60 languages](http://rouge.jayferd.us/demo), no configuration required. 24 | 25 | * **Automatic, smoothly scrolling table of contents** on the far left of the page. As you scroll, it displays your current position in the document. It's fast, too. We're using Slate at TripIt to build documentation for our new API, where our table of contents has over 180 entries. We've made sure that the performance remains excellent, even for larger documents. 26 | 27 | * **Let your users update your documentation for you** — by default, your Slate-generated documentation is hosted in a public Github repository. Not only does this mean you get free hosting for your docs with Github Pages, but it also makes it's simple for other developers to make pull requests to your docs if they find typos or other problems. Of course, if you don't want to, you're welcome to not use Github and host your docs elsewhere! 28 | 29 | Getting starting with Slate is super easy! Simply fork this repository, and then follow the instructions below. Or, if you'd like to check out what Slate is capable of, take a look at the [sample docs](http://tripit.github.io/slate). 30 | 31 | 32 | 33 | Getting Started with Slate 34 | ------------------------------ 35 | 36 | ### Prerequisites 37 | 38 | You're going to need: 39 | 40 | - **Linux or OS X** — Windows may work, but is unsupported. 41 | - **Ruby, version 1.9.3 or newer** 42 | - **Bundler** — If Ruby is already installed, but the `bundle` command doesn't work, just run `gem install bundler` in a terminal. 43 | 44 | ### Getting Set Up 45 | 46 | 1. Fork this repository on Github. 47 | 2. Clone *your forked repository* (not our original one) to your hard drive with `git clone https://github.com/YOURUSERNAME/slate.git` 48 | 3. `cd slate` 49 | 4. Install all dependencies: `bundle install` 50 | 5. Start the test server: `bundle exec middleman server` 51 | 52 | Or use the included Dockerfile! (must install Docker first) 53 | 54 | ```shell 55 | docker build -t slate . 56 | docker run -d -p 4567:4567 slate 57 | ``` 58 | 59 | You can now see the docs at . Whoa! That was fast! 60 | 61 | *Note: if you're using the Docker setup on OSX, the docs will be 62 | availalable at the output of `boot2docker ip` instead of `localhost:4567`.* 63 | 64 | Now that Slate is all set up your machine, you'll probably want to learn more about [editing Slate markdown](https://github.com/tripit/slate/wiki/Markdown-Syntax), or [how to publish your docs](https://github.com/tripit/slate/wiki/Deploying-Slate). 65 | 66 | Examples of Slate in the Wild 67 | --------------------------------- 68 | 69 | * [Travis-CI's API docs](http://docs.travis-ci.com/api/) 70 | * [Mozilla's localForage docs](http://mozilla.github.io/localForage/) 71 | * [Mozilla Recroom](http://mozilla.github.io/recroom/) 72 | * [ChaiOne Gameplan API docs](http://chaione.github.io/gameplanb2b/#introduction) 73 | * [Drcaban's Build a Quine tutorial](http://drcabana.github.io/build-a-quine/#introduction) 74 | * [PricePlow API docs](https://www.priceplow.com/api/documentation) 75 | * [Emerging Threats API docs](http://apidocs.emergingthreats.net/) 76 | * [Appium docs](http://appium.io/slate/en/master) 77 | * [Golazon Developer](http://developer.golazon.com) 78 | * [Dwolla API docs](https://docs.dwolla.com/) 79 | * [RozpisyZapasu API docs](http://www.rozpisyzapasu.cz/dev/api/) 80 | * [Codestar Framework Docs](http://codestarframework.com/documentation/) 81 | * [Buddycloud API](http://buddycloud.com/api) 82 | * [Crafty Clicks API](https://craftyclicks.co.uk/api/) 83 | * [Paracel API Reference](http://paracel.io/docs/api_reference.html) 84 | * [Switch Payments Documentation](http://switchpayments.com/docs/) & [API](http://switchpayments.com/developers/) 85 | * [Coinbase API Reference](https://developers.coinbase.com/api) 86 | * [Whispir.io API](https://whispir.github.io/api) 87 | * [NASA API](https://data.nasa.gov/developer/external/planetary/) 88 | * [CardPay API](https://developers.cardpay.com/) 89 | * [IBM Cloudant](https://docs-testb.cloudant.com/content-review/_design/couchapp/index.html) 90 | * [Bitrix basis components](http://bbc.bitrix.expert/) 91 | 92 | (Feel free to add your site to this list in a pull request!) 93 | 94 | Need Help? Found a bug? 95 | -------------------- 96 | 97 | Just [submit a issue](https://github.com/tripit/slate/issues) to the Slate Github if you need any help. And, of course, feel free to submit pull requests with bug fixes or changes. 98 | 99 | 100 | Contributors 101 | -------------------- 102 | 103 | Slate was built by [Robert Lord](http://lord.io) while at [TripIt](http://tripit.com). 104 | 105 | Thanks to the following people who have submitted major pull requests: 106 | 107 | - [@chrissrogers](https://github.com/chrissrogers) 108 | - [@bootstraponline](https://github.com/bootstraponline) 109 | - [@realityking](https://github.com/realityking) 110 | 111 | Also, thanks to [Sauce Labs](http://saucelabs.com) for helping sponsor the project. 112 | 113 | Special Thanks 114 | -------------------- 115 | - [Middleman](https://github.com/middleman/middleman) 116 | - [jquery.tocify.js](https://github.com/gfranko/jquery.tocify.js) 117 | - [middleman-syntax](https://github.com/middleman/middleman-syntax) 118 | - [middleman-gh-pages](https://github.com/neo/middleman-gh-pages) 119 | - [Font Awesome](http://fortawesome.github.io/Font-Awesome/) 120 | -------------------------------------------------------------------------------- /app/docs/slate/source/stylesheets/_normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS text size adjust after orientation change, without disabling 6 | * user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -ms-text-size-adjust: 100%; /* 2 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | * and Firefox. 30 | * Correct `block` display not defined for `main` in IE 11. 31 | */ 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | /** 50 | * 1. Correct `inline-block` display not defined in IE 8/9. 51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | */ 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; /* 1 */ 59 | vertical-align: baseline; /* 2 */ 60 | } 61 | 62 | /** 63 | * Prevent modern browsers from displaying `audio` without controls. 64 | * Remove excess height in iOS 5 devices. 65 | */ 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | /** 73 | * Address `[hidden]` styling not present in IE 8/9/10. 74 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. 75 | */ 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | /* Links 83 | ========================================================================== */ 84 | 85 | /** 86 | * Remove the gray background color from active links in IE 10. 87 | */ 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | /** 94 | * Improve readability when focused and also mouse hovered in all browsers. 95 | */ 96 | 97 | a:active, 98 | a:hover { 99 | outline: 0; 100 | } 101 | 102 | /* Text-level semantics 103 | ========================================================================== */ 104 | 105 | /** 106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 107 | */ 108 | 109 | abbr[title] { 110 | border-bottom: 1px dotted; 111 | } 112 | 113 | /** 114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 115 | */ 116 | 117 | b, 118 | strong { 119 | font-weight: bold; 120 | } 121 | 122 | /** 123 | * Address styling not present in Safari and Chrome. 124 | */ 125 | 126 | dfn { 127 | font-style: italic; 128 | } 129 | 130 | /** 131 | * Address variable `h1` font-size and margin within `section` and `article` 132 | * contexts in Firefox 4+, Safari, and Chrome. 133 | */ 134 | 135 | h1 { 136 | font-size: 2em; 137 | margin: 0.67em 0; 138 | } 139 | 140 | /** 141 | * Address styling not present in IE 8/9. 142 | */ 143 | 144 | mark { 145 | background: #ff0; 146 | color: #000; 147 | } 148 | 149 | /** 150 | * Address inconsistent and variable font size in all browsers. 151 | */ 152 | 153 | small { 154 | font-size: 80%; 155 | } 156 | 157 | /** 158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 159 | */ 160 | 161 | sub, 162 | sup { 163 | font-size: 75%; 164 | line-height: 0; 165 | position: relative; 166 | vertical-align: baseline; 167 | } 168 | 169 | sup { 170 | top: -0.5em; 171 | } 172 | 173 | sub { 174 | bottom: -0.25em; 175 | } 176 | 177 | /* Embedded content 178 | ========================================================================== */ 179 | 180 | /** 181 | * Remove border when inside `a` element in IE 8/9/10. 182 | */ 183 | 184 | img { 185 | border: 0; 186 | } 187 | 188 | /** 189 | * Correct overflow not hidden in IE 9/10/11. 190 | */ 191 | 192 | svg:not(:root) { 193 | overflow: hidden; 194 | } 195 | 196 | /* Grouping content 197 | ========================================================================== */ 198 | 199 | /** 200 | * Address margin not present in IE 8/9 and Safari. 201 | */ 202 | 203 | figure { 204 | margin: 1em 40px; 205 | } 206 | 207 | /** 208 | * Address differences between Firefox and other browsers. 209 | */ 210 | 211 | hr { 212 | -moz-box-sizing: content-box; 213 | box-sizing: content-box; 214 | height: 0; 215 | } 216 | 217 | /** 218 | * Contain overflow in all browsers. 219 | */ 220 | 221 | pre { 222 | overflow: auto; 223 | } 224 | 225 | /** 226 | * Address odd `em`-unit font size rendering in all browsers. 227 | */ 228 | 229 | code, 230 | kbd, 231 | pre, 232 | samp { 233 | font-family: monospace, monospace; 234 | font-size: 1em; 235 | } 236 | 237 | /* Forms 238 | ========================================================================== */ 239 | 240 | /** 241 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 242 | * styling of `select`, unless a `border` property is set. 243 | */ 244 | 245 | /** 246 | * 1. Correct color not being inherited. 247 | * Known issue: affects color of disabled elements. 248 | * 2. Correct font properties not being inherited. 249 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 | */ 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | color: inherit; /* 1 */ 258 | font: inherit; /* 2 */ 259 | margin: 0; /* 3 */ 260 | } 261 | 262 | /** 263 | * Address `overflow` set to `hidden` in IE 8/9/10/11. 264 | */ 265 | 266 | button { 267 | overflow: visible; 268 | } 269 | 270 | /** 271 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 272 | * All other form control elements do not inherit `text-transform` values. 273 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 | * Correct `select` style inheritance in Firefox. 275 | */ 276 | 277 | button, 278 | select { 279 | text-transform: none; 280 | } 281 | 282 | /** 283 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 | * and `video` controls. 285 | * 2. Correct inability to style clickable `input` types in iOS. 286 | * 3. Improve usability and consistency of cursor style between image-type 287 | * `input` and others. 288 | */ 289 | 290 | button, 291 | html input[type="button"], /* 1 */ 292 | input[type="reset"], 293 | input[type="submit"] { 294 | -webkit-appearance: button; /* 2 */ 295 | cursor: pointer; /* 3 */ 296 | } 297 | 298 | /** 299 | * Re-set default cursor for disabled elements. 300 | */ 301 | 302 | button[disabled], 303 | html input[disabled] { 304 | cursor: default; 305 | } 306 | 307 | /** 308 | * Remove inner padding and border in Firefox 4+. 309 | */ 310 | 311 | button::-moz-focus-inner, 312 | input::-moz-focus-inner { 313 | border: 0; 314 | padding: 0; 315 | } 316 | 317 | /** 318 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 | * the UA stylesheet. 320 | */ 321 | 322 | input { 323 | line-height: normal; 324 | } 325 | 326 | /** 327 | * It's recommended that you don't attempt to style these elements. 328 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 329 | * 330 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 331 | * 2. Remove excess padding in IE 8/9/10. 332 | */ 333 | 334 | input[type="checkbox"], 335 | input[type="radio"] { 336 | box-sizing: border-box; /* 1 */ 337 | padding: 0; /* 2 */ 338 | } 339 | 340 | /** 341 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 | * `font-size` values of the `input`, it causes the cursor style of the 343 | * decrement button to change from `default` to `text`. 344 | */ 345 | 346 | input[type="number"]::-webkit-inner-spin-button, 347 | input[type="number"]::-webkit-outer-spin-button { 348 | height: auto; 349 | } 350 | 351 | /** 352 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome 354 | * (include `-moz` to future-proof). 355 | */ 356 | 357 | input[type="search"] { 358 | -webkit-appearance: textfield; /* 1 */ 359 | -moz-box-sizing: content-box; 360 | -webkit-box-sizing: content-box; /* 2 */ 361 | box-sizing: content-box; 362 | } 363 | 364 | /** 365 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 366 | * Safari (but not Chrome) clips the cancel button when the search input has 367 | * padding (and `textfield` appearance). 368 | */ 369 | 370 | input[type="search"]::-webkit-search-cancel-button, 371 | input[type="search"]::-webkit-search-decoration { 372 | -webkit-appearance: none; 373 | } 374 | 375 | /** 376 | * Define consistent border, margin, and padding. 377 | */ 378 | 379 | fieldset { 380 | border: 1px solid #c0c0c0; 381 | margin: 0 2px; 382 | padding: 0.35em 0.625em 0.75em; 383 | } 384 | 385 | /** 386 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 387 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 388 | */ 389 | 390 | legend { 391 | border: 0; /* 1 */ 392 | padding: 0; /* 2 */ 393 | } 394 | 395 | /** 396 | * Remove default vertical scrollbar in IE 8/9/10/11. 397 | */ 398 | 399 | textarea { 400 | overflow: auto; 401 | } 402 | 403 | /** 404 | * Don't inherit the `font-weight` (applied by a rule above). 405 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 406 | */ 407 | 408 | optgroup { 409 | font-weight: bold; 410 | } 411 | 412 | /* Tables 413 | ========================================================================== */ 414 | 415 | /** 416 | * Remove most spacing between table cells. 417 | */ 418 | 419 | table { 420 | border-collapse: collapse; 421 | border-spacing: 0; 422 | } 423 | 424 | td, 425 | th { 426 | padding: 0; 427 | } 428 | -------------------------------------------------------------------------------- /app/docs/slate/source/stylesheets/screen.css.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @import 'normalize'; 3 | @import 'compass'; 4 | @import 'variables'; 5 | @import 'syntax'; 6 | @import 'icon-font'; 7 | 8 | /* 9 | Copyright 2008-2013 Concur Technologies, Inc. 10 | 11 | Licensed under the Apache License, Version 2.0 (the "License"); you may 12 | not use this file except in compliance with the License. You may obtain 13 | a copy of the License at 14 | 15 | http://www.apache.org/licenses/LICENSE-2.0 16 | 17 | Unless required by applicable law or agreed to in writing, software 18 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 19 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 20 | License for the specific language governing permissions and limitations 21 | under the License. 22 | */ 23 | 24 | //////////////////////////////////////////////////////////////////////////////// 25 | // GENERAL STUFF 26 | //////////////////////////////////////////////////////////////////////////////// 27 | 28 | html, body { 29 | color: $main-text; 30 | padding: 0; 31 | margin: 0; 32 | -webkit-font-smoothing: antialiased; 33 | -moz-osx-font-smoothing: grayscale; 34 | @extend %default-font; 35 | background-color: $main-bg; 36 | height: 100%; 37 | -webkit-text-size-adjust: none; /* Never autoresize text */ 38 | } 39 | 40 | //////////////////////////////////////////////////////////////////////////////// 41 | // TABLE OF CONTENTS 42 | //////////////////////////////////////////////////////////////////////////////// 43 | 44 | #toc > ul > li > a > span { 45 | float: right; 46 | background-color: #2484FF; 47 | border-radius: 40px; 48 | width: 20px; 49 | } 50 | 51 | @mixin embossed-bg { 52 | @include background( 53 | linear-gradient(top, 54 | rgba(#000, 0.2), 55 | rgba(#000, 0) 8px), 56 | linear-gradient(bottom, 57 | rgba(#000, 0.2), 58 | rgba(#000, 0) 8px), 59 | linear-gradient(top, 60 | rgba($nav-embossed-border-top, 1), 61 | rgba($nav-embossed-border-top, 0) 1.5px), 62 | linear-gradient(bottom, 63 | rgba($nav-embossed-border-bottom, 1), 64 | rgba($nav-embossed-border-bottom, 0) 1.5px), 65 | $nav-subitem-bg 66 | ); 67 | } 68 | 69 | .tocify-wrapper { 70 | @include transition(left ease-in-out 0.3s); 71 | overflow-y: auto; 72 | overflow-x: hidden; 73 | position: fixed; 74 | z-index: 30; 75 | top: 0; 76 | left: 0; 77 | bottom: 0; 78 | width: $nav-width; 79 | background-color: $nav-bg; 80 | font-size: 13px; 81 | font-weight: bold; 82 | 83 | // language selector for mobile devices 84 | .lang-selector { 85 | display: none; 86 | a { 87 | padding-top: 0.5em; 88 | padding-bottom: 0.5em; 89 | } 90 | } 91 | 92 | // This is the logo at the top of the ToC 93 | &>img { 94 | display: block; 95 | } 96 | 97 | &>.search { 98 | position: relative; 99 | 100 | input { 101 | background: $nav-bg; 102 | border-width: 0 0 1px 0; 103 | border-color: $search-box-border-color; 104 | padding: 6px 0 6px 20px; 105 | @include box-sizing(border-box); 106 | margin: $nav-v-padding $nav-padding; 107 | width: $nav-width - 30; 108 | outline: none; 109 | color: $nav-text; 110 | border-radius: 0; /* ios has a default border radius */ 111 | } 112 | 113 | &:before { 114 | position: absolute; 115 | top: 17px; 116 | left: $nav-padding; 117 | color: $nav-text; 118 | @extend %icon-search; 119 | } 120 | } 121 | 122 | img+.tocify { 123 | margin-top: $logo-margin; 124 | } 125 | 126 | .search-results { 127 | margin-top: 0; 128 | @include box-sizing(border-box); 129 | height: 0; 130 | overflow-y: auto; 131 | overflow-x: hidden; 132 | @include transition-property(height margin); 133 | @include transition-duration(180ms); 134 | @include transition-timing-function(ease-in-out); 135 | &.visible { 136 | height: 30%; 137 | margin-bottom: 1em; 138 | } 139 | 140 | @include embossed-bg; 141 | 142 | li { 143 | margin: 1em $nav-padding; 144 | line-height: 1; 145 | } 146 | 147 | a { 148 | color: $nav-text; 149 | text-decoration: none; 150 | 151 | &:hover { 152 | text-decoration: underline; 153 | } 154 | } 155 | } 156 | 157 | 158 | .tocify-item>a, .toc-footer li { 159 | padding: 0 $nav-padding 0 $nav-padding; 160 | display: block; 161 | overflow-x: hidden; 162 | white-space: nowrap; 163 | text-overflow: ellipsis; 164 | } 165 | 166 | // The Table of Contents is composed of multiple nested 167 | // unordered lists. These styles remove the default 168 | // styling of an unordered list because it is ugly. 169 | ul, li { 170 | list-style: none; 171 | margin: 0; 172 | padding: 0; 173 | line-height: 28px; 174 | } 175 | 176 | li { 177 | color: $nav-text; 178 | @include transition-property('background'); 179 | @include transition-timing-function('linear'); 180 | @include transition-duration(230ms); 181 | } 182 | 183 | // This is the currently selected ToC entry 184 | .tocify-focus { 185 | @include box-shadow(0px 1px 0px $nav-active-shadow); 186 | background-color: $nav-active-bg; 187 | color: $nav-active-text; 188 | } 189 | 190 | // Subheaders are the submenus that slide open 191 | // in the table of contents. 192 | .tocify-subheader { 193 | display: none; // tocify will override this when needed 194 | background-color: $nav-subitem-bg; 195 | font-weight: 500; 196 | .tocify-item>a { 197 | padding-left: $nav-padding + $nav-indent; 198 | font-size: 12px; 199 | } 200 | 201 | // for embossed look: 202 | @include embossed-bg; 203 | &>li:last-child { 204 | box-shadow: none; // otherwise it'll overflow out of the subheader 205 | } 206 | } 207 | 208 | .toc-footer { 209 | padding: 1em 0; 210 | margin-top: 1em; 211 | border-top: 1px dashed $nav-footer-border-color; 212 | 213 | li,a { 214 | color: $nav-text; 215 | text-decoration: none; 216 | } 217 | 218 | a:hover { 219 | text-decoration: underline; 220 | } 221 | 222 | li { 223 | font-size: 0.8em; 224 | line-height: 1.7; 225 | text-decoration: none; 226 | } 227 | } 228 | 229 | } 230 | 231 | // button to show navigation on mobile devices 232 | #nav-button { 233 | span { 234 | display: block; 235 | $side-pad: $main-padding / 2 - 8px; 236 | padding: $side-pad $side-pad $side-pad; 237 | background-color: rgba($main-bg, 0.7); 238 | @include transform-origin(0, 0); 239 | @include transform(rotate(-90deg) translate(-100%, 0)); 240 | border-radius: 0 0 0 5px; 241 | } 242 | padding: 0 1.5em 5em 0; // increase touch size area 243 | display: none; 244 | position: fixed; 245 | top: 0; 246 | left: 0; 247 | z-index: 100; 248 | color: #000; 249 | text-decoration: none; 250 | font-weight: bold; 251 | opacity: 0.7; 252 | line-height: 16px; 253 | img { 254 | height: 16px; 255 | vertical-align: bottom; 256 | } 257 | 258 | @include transition(left ease-in-out 0.3s); 259 | 260 | &:hover { opacity: 1; } 261 | &.open {left: $nav-width} 262 | } 263 | 264 | 265 | //////////////////////////////////////////////////////////////////////////////// 266 | // PAGE LAYOUT AND CODE SAMPLE BACKGROUND 267 | //////////////////////////////////////////////////////////////////////////////// 268 | 269 | .page-wrapper { 270 | margin-left: $nav-width; 271 | position: relative; 272 | z-index: 10; 273 | background-color: $main-bg; 274 | min-height: 100%; 275 | 276 | padding-bottom: 1px; // prevent margin overflow 277 | 278 | // The dark box is what gives the code samples their dark background. 279 | // It sits essentially under the actual content block, which has a 280 | // transparent background. 281 | // I know, it's hackish, but it's the simplist way to make the left 282 | // half of the content always this background color. 283 | .dark-box { 284 | width: $examples-width; 285 | background-color: $examples-bg; 286 | position: absolute; 287 | right: 0; 288 | top: 0; 289 | bottom: 0; 290 | } 291 | 292 | .lang-selector { 293 | position: fixed; 294 | z-index: 50; 295 | border-bottom: 5px solid $lang-select-active-bg; 296 | } 297 | } 298 | 299 | .lang-selector { 300 | background-color: $lang-select-bg; 301 | width: 100%; 302 | font-weight: bold; 303 | a { 304 | display: block; 305 | float:left; 306 | color: $lang-select-text; 307 | text-decoration: none; 308 | padding: 0 10px; 309 | line-height: 30px; 310 | outline: 0; 311 | 312 | &:active, &:focus { 313 | background-color: $lang-select-pressed-bg; 314 | color: $lang-select-pressed-text; 315 | } 316 | 317 | &.active { 318 | background-color: $lang-select-active-bg; 319 | color: $lang-select-active-text; 320 | } 321 | } 322 | 323 | &:after { 324 | content: ''; 325 | clear: both; 326 | display: block; 327 | } 328 | } 329 | 330 | //////////////////////////////////////////////////////////////////////////////// 331 | // CONTENT STYLES 332 | //////////////////////////////////////////////////////////////////////////////// 333 | // This is all the stuff with the light background in the left half of the page 334 | 335 | .content { 336 | // to place content above the dark box 337 | position: relative; 338 | z-index: 30; 339 | 340 | &:after { 341 | content: ''; 342 | display: block; 343 | clear: both; 344 | } 345 | 346 | &>h1, &>h2, &>h3, &>h4, &>h5, &>h6, &>p, &>table, &>ul, &>ol, &>aside, &>dl { 347 | margin-right: $examples-width; 348 | padding: 0 $main-padding; 349 | @include box-sizing(border-box); 350 | display: block; 351 | @include text-shadow($main-embossed-text-shadow); 352 | 353 | @extend %left-col; 354 | } 355 | 356 | &>ul, &>ol { 357 | padding-left: $main-padding + 15px; 358 | } 359 | 360 | // the div is the tocify hidden div for placeholding stuff 361 | &>h1, &>h2, &>div { 362 | clear:both; 363 | } 364 | 365 | h1 { 366 | @extend %header-font; 367 | font-size: 30px; 368 | padding-top: 0.5em; 369 | padding-bottom: 0.5em; 370 | border-bottom: 1px solid #ccc; 371 | margin-bottom: $h1-margin-bottom; 372 | margin-top: 2em; 373 | border-top: 1px solid #ddd; 374 | @include background-image( 375 | linear-gradient(top, #fff, #f9f9f9) 376 | ); 377 | } 378 | 379 | h1:first-child, div:first-child + h1 { 380 | border-top-width: 0; 381 | margin-top: 0; 382 | } 383 | 384 | h2 { 385 | @extend %header-font; 386 | font-size: 20px; 387 | margin-top: 4em; 388 | margin-bottom: 0; 389 | border-top: 1px solid #ccc; 390 | padding-top: 1.2em; 391 | padding-bottom: 1.2em; 392 | @include background-image( 393 | linear-gradient(top, rgba(#fff,0.4), rgba(#fff, 0)) 394 | ); 395 | } 396 | 397 | // h2s right after h1s should bump right up 398 | // against the h1s. 399 | h1 + h2, h1 + div + h2 { 400 | margin-top: $h1-margin-bottom * -1; 401 | border-top: none; 402 | } 403 | 404 | h3, h4, h5, h6 { 405 | @extend %header-font; 406 | font-size: 12px; 407 | margin-top: 2.5em; 408 | margin-bottom: 0.8em; 409 | text-transform: uppercase; 410 | } 411 | 412 | h4, h5, h6 { 413 | font-size: 10px; 414 | } 415 | 416 | hr { 417 | margin: 2em 0; 418 | border-top: 2px solid $examples-bg; 419 | border-bottom: 2px solid $main-bg; 420 | } 421 | 422 | table { 423 | margin-bottom: 1em; 424 | overflow: auto; 425 | th,td { 426 | text-align: left; 427 | vertical-align: top; 428 | line-height: 1.6; 429 | } 430 | 431 | th { 432 | padding: 5px 10px; 433 | border-bottom: 1px solid #ccc; 434 | vertical-align: bottom; 435 | } 436 | 437 | td { 438 | padding: 10px; 439 | } 440 | 441 | tr:last-child { 442 | border-bottom: 1px solid #ccc; 443 | } 444 | 445 | tr:nth-child(odd)>td { 446 | background-color: lighten($main-bg,4.2%); 447 | } 448 | 449 | tr:nth-child(even)>td { 450 | background-color: lighten($main-bg,2.4%); 451 | } 452 | } 453 | 454 | dt { 455 | font-weight: bold; 456 | } 457 | 458 | dd { 459 | margin-left: 15px; 460 | } 461 | 462 | p, li, dt, dd { 463 | line-height: 1.6; 464 | margin-top: 0; 465 | } 466 | 467 | img { 468 | max-width: 100%; 469 | } 470 | 471 | code { 472 | background-color: rgba(0,0,0,0.05); 473 | padding: 3px; 474 | border-radius: 3px; 475 | @extend %break-words; 476 | @extend %code-font; 477 | } 478 | 479 | pre>code { 480 | background-color: transparent; 481 | padding: 0; 482 | } 483 | 484 | aside { 485 | padding-top: 1em; 486 | padding-bottom: 1em; 487 | @include text-shadow(0 1px 0 lighten($aside-notice-bg, 15%)); 488 | margin-top: 1.5em; 489 | margin-bottom: 1.5em; 490 | background: $aside-notice-bg; 491 | line-height: 1.6; 492 | 493 | &.warning { 494 | background-color: $aside-warning-bg; 495 | @include text-shadow(0 1px 0 lighten($aside-warning-bg, 15%)); 496 | } 497 | 498 | &.success { 499 | background-color: $aside-success-bg; 500 | @include text-shadow(0 1px 0 lighten($aside-success-bg, 15%)); 501 | } 502 | } 503 | 504 | aside:before { 505 | vertical-align: middle; 506 | padding-right: 0.5em; 507 | font-size: 14px; 508 | } 509 | 510 | aside.notice:before { 511 | @extend %icon-info-sign; 512 | } 513 | 514 | aside.warning:before { 515 | @extend %icon-exclamation-sign; 516 | } 517 | 518 | aside.success:before { 519 | @extend %icon-ok-sign; 520 | } 521 | 522 | .search-highlight { 523 | padding: 2px; 524 | margin: -2px; 525 | border-radius: 4px; 526 | border: 1px solid #F7E633; 527 | @include text-shadow(1px 1px 0 #666); 528 | @include background(linear-gradient(bottom right, #F7E633 0%, #F1D32F 100%)); 529 | } 530 | } 531 | 532 | //////////////////////////////////////////////////////////////////////////////// 533 | // CODE SAMPLE STYLES 534 | //////////////////////////////////////////////////////////////////////////////// 535 | // This is all the stuff that appears in the right half of the page 536 | 537 | .content { 538 | pre, blockquote { 539 | background-color: $code-bg; 540 | color: #fff; 541 | 542 | padding: 2em $main-padding; 543 | margin: 0; 544 | width: $examples-width; 545 | 546 | float:right; 547 | clear:right; 548 | 549 | @include box-sizing(border-box); 550 | @include text-shadow(0px 1px 2px rgba(0,0,0,0.4)); 551 | 552 | @extend %right-col; 553 | 554 | &>p { margin: 0; } 555 | 556 | a { 557 | color: #fff; 558 | text-decoration: none; 559 | border-bottom: dashed 1px #ccc; 560 | } 561 | } 562 | 563 | pre { 564 | @extend %code-font; 565 | } 566 | 567 | blockquote { 568 | &>p { 569 | background-color: $code-annotation-bg; 570 | border-radius: 5px; 571 | padding: $code-annotation-padding; 572 | color: #ccc; 573 | border-top: 1px solid #000; 574 | border-bottom: 1px solid #404040; 575 | } 576 | } 577 | } 578 | 579 | //////////////////////////////////////////////////////////////////////////////// 580 | // RESPONSIVE DESIGN 581 | //////////////////////////////////////////////////////////////////////////////// 582 | // These are the styles for phones and tablets 583 | // There are also a couple styles disperesed 584 | 585 | @media (max-width: $tablet-width) { 586 | .tocify-wrapper { 587 | left: -$nav-width; 588 | 589 | &.open { 590 | left: 0; 591 | } 592 | } 593 | 594 | .page-wrapper { 595 | margin-left: 0; 596 | } 597 | 598 | #nav-button { 599 | display: block; 600 | } 601 | 602 | .tocify-wrapper .tocify-item > a { 603 | padding-top: 0.3em; 604 | padding-bottom: 0.3em; 605 | } 606 | } 607 | 608 | @media (max-width: $phone-width) { 609 | .dark-box { 610 | display: none; 611 | } 612 | 613 | %left-col { 614 | margin-right: 0; 615 | } 616 | 617 | .tocify-wrapper .lang-selector { 618 | display: block; 619 | } 620 | 621 | .page-wrapper .lang-selector { 622 | display: none; 623 | } 624 | 625 | %right-col { 626 | width: auto; 627 | float: none; 628 | } 629 | 630 | %right-col + %left-col { 631 | margin-top: $main-padding; 632 | } 633 | } 634 | -------------------------------------------------------------------------------- /app/docs/slate/source/javascripts/lib/jquery_ui.js: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.11.3 - 2015-02-12 2 | * http://jqueryui.com 3 | * Includes: widget.js 4 | * Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ 5 | 6 | (function( factory ) { 7 | if ( typeof define === "function" && define.amd ) { 8 | 9 | // AMD. Register as an anonymous module. 10 | define([ "jquery" ], factory ); 11 | } else { 12 | 13 | // Browser globals 14 | factory( jQuery ); 15 | } 16 | }(function( $ ) { 17 | /*! 18 | * jQuery UI Widget 1.11.3 19 | * http://jqueryui.com 20 | * 21 | * Copyright jQuery Foundation and other contributors 22 | * Released under the MIT license. 23 | * http://jquery.org/license 24 | * 25 | * http://api.jqueryui.com/jQuery.widget/ 26 | */ 27 | 28 | 29 | var widget_uuid = 0, 30 | widget_slice = Array.prototype.slice; 31 | 32 | $.cleanData = (function( orig ) { 33 | return function( elems ) { 34 | var events, elem, i; 35 | for ( i = 0; (elem = elems[i]) != null; i++ ) { 36 | try { 37 | 38 | // Only trigger remove when necessary to save time 39 | events = $._data( elem, "events" ); 40 | if ( events && events.remove ) { 41 | $( elem ).triggerHandler( "remove" ); 42 | } 43 | 44 | // http://bugs.jquery.com/ticket/8235 45 | } catch ( e ) {} 46 | } 47 | orig( elems ); 48 | }; 49 | })( $.cleanData ); 50 | 51 | $.widget = function( name, base, prototype ) { 52 | var fullName, existingConstructor, constructor, basePrototype, 53 | // proxiedPrototype allows the provided prototype to remain unmodified 54 | // so that it can be used as a mixin for multiple widgets (#8876) 55 | proxiedPrototype = {}, 56 | namespace = name.split( "." )[ 0 ]; 57 | 58 | name = name.split( "." )[ 1 ]; 59 | fullName = namespace + "-" + name; 60 | 61 | if ( !prototype ) { 62 | prototype = base; 63 | base = $.Widget; 64 | } 65 | 66 | // create selector for plugin 67 | $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { 68 | return !!$.data( elem, fullName ); 69 | }; 70 | 71 | $[ namespace ] = $[ namespace ] || {}; 72 | existingConstructor = $[ namespace ][ name ]; 73 | constructor = $[ namespace ][ name ] = function( options, element ) { 74 | // allow instantiation without "new" keyword 75 | if ( !this._createWidget ) { 76 | return new constructor( options, element ); 77 | } 78 | 79 | // allow instantiation without initializing for simple inheritance 80 | // must use "new" keyword (the code above always passes args) 81 | if ( arguments.length ) { 82 | this._createWidget( options, element ); 83 | } 84 | }; 85 | // extend with the existing constructor to carry over any static properties 86 | $.extend( constructor, existingConstructor, { 87 | version: prototype.version, 88 | // copy the object used to create the prototype in case we need to 89 | // redefine the widget later 90 | _proto: $.extend( {}, prototype ), 91 | // track widgets that inherit from this widget in case this widget is 92 | // redefined after a widget inherits from it 93 | _childConstructors: [] 94 | }); 95 | 96 | basePrototype = new base(); 97 | // we need to make the options hash a property directly on the new instance 98 | // otherwise we'll modify the options hash on the prototype that we're 99 | // inheriting from 100 | basePrototype.options = $.widget.extend( {}, basePrototype.options ); 101 | $.each( prototype, function( prop, value ) { 102 | if ( !$.isFunction( value ) ) { 103 | proxiedPrototype[ prop ] = value; 104 | return; 105 | } 106 | proxiedPrototype[ prop ] = (function() { 107 | var _super = function() { 108 | return base.prototype[ prop ].apply( this, arguments ); 109 | }, 110 | _superApply = function( args ) { 111 | return base.prototype[ prop ].apply( this, args ); 112 | }; 113 | return function() { 114 | var __super = this._super, 115 | __superApply = this._superApply, 116 | returnValue; 117 | 118 | this._super = _super; 119 | this._superApply = _superApply; 120 | 121 | returnValue = value.apply( this, arguments ); 122 | 123 | this._super = __super; 124 | this._superApply = __superApply; 125 | 126 | return returnValue; 127 | }; 128 | })(); 129 | }); 130 | constructor.prototype = $.widget.extend( basePrototype, { 131 | // TODO: remove support for widgetEventPrefix 132 | // always use the name + a colon as the prefix, e.g., draggable:start 133 | // don't prefix for widgets that aren't DOM-based 134 | widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name 135 | }, proxiedPrototype, { 136 | constructor: constructor, 137 | namespace: namespace, 138 | widgetName: name, 139 | widgetFullName: fullName 140 | }); 141 | 142 | // If this widget is being redefined then we need to find all widgets that 143 | // are inheriting from it and redefine all of them so that they inherit from 144 | // the new version of this widget. We're essentially trying to replace one 145 | // level in the prototype chain. 146 | if ( existingConstructor ) { 147 | $.each( existingConstructor._childConstructors, function( i, child ) { 148 | var childPrototype = child.prototype; 149 | 150 | // redefine the child widget using the same prototype that was 151 | // originally used, but inherit from the new version of the base 152 | $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); 153 | }); 154 | // remove the list of existing child constructors from the old constructor 155 | // so the old child constructors can be garbage collected 156 | delete existingConstructor._childConstructors; 157 | } else { 158 | base._childConstructors.push( constructor ); 159 | } 160 | 161 | $.widget.bridge( name, constructor ); 162 | 163 | return constructor; 164 | }; 165 | 166 | $.widget.extend = function( target ) { 167 | var input = widget_slice.call( arguments, 1 ), 168 | inputIndex = 0, 169 | inputLength = input.length, 170 | key, 171 | value; 172 | for ( ; inputIndex < inputLength; inputIndex++ ) { 173 | for ( key in input[ inputIndex ] ) { 174 | value = input[ inputIndex ][ key ]; 175 | if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { 176 | // Clone objects 177 | if ( $.isPlainObject( value ) ) { 178 | target[ key ] = $.isPlainObject( target[ key ] ) ? 179 | $.widget.extend( {}, target[ key ], value ) : 180 | // Don't extend strings, arrays, etc. with objects 181 | $.widget.extend( {}, value ); 182 | // Copy everything else by reference 183 | } else { 184 | target[ key ] = value; 185 | } 186 | } 187 | } 188 | } 189 | return target; 190 | }; 191 | 192 | $.widget.bridge = function( name, object ) { 193 | var fullName = object.prototype.widgetFullName || name; 194 | $.fn[ name ] = function( options ) { 195 | var isMethodCall = typeof options === "string", 196 | args = widget_slice.call( arguments, 1 ), 197 | returnValue = this; 198 | 199 | if ( isMethodCall ) { 200 | this.each(function() { 201 | var methodValue, 202 | instance = $.data( this, fullName ); 203 | if ( options === "instance" ) { 204 | returnValue = instance; 205 | return false; 206 | } 207 | if ( !instance ) { 208 | return $.error( "cannot call methods on " + name + " prior to initialization; " + 209 | "attempted to call method '" + options + "'" ); 210 | } 211 | if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { 212 | return $.error( "no such method '" + options + "' for " + name + " widget instance" ); 213 | } 214 | methodValue = instance[ options ].apply( instance, args ); 215 | if ( methodValue !== instance && methodValue !== undefined ) { 216 | returnValue = methodValue && methodValue.jquery ? 217 | returnValue.pushStack( methodValue.get() ) : 218 | methodValue; 219 | return false; 220 | } 221 | }); 222 | } else { 223 | 224 | // Allow multiple hashes to be passed on init 225 | if ( args.length ) { 226 | options = $.widget.extend.apply( null, [ options ].concat(args) ); 227 | } 228 | 229 | this.each(function() { 230 | var instance = $.data( this, fullName ); 231 | if ( instance ) { 232 | instance.option( options || {} ); 233 | if ( instance._init ) { 234 | instance._init(); 235 | } 236 | } else { 237 | $.data( this, fullName, new object( options, this ) ); 238 | } 239 | }); 240 | } 241 | 242 | return returnValue; 243 | }; 244 | }; 245 | 246 | $.Widget = function( /* options, element */ ) {}; 247 | $.Widget._childConstructors = []; 248 | 249 | $.Widget.prototype = { 250 | widgetName: "widget", 251 | widgetEventPrefix: "", 252 | defaultElement: "
      ", 253 | options: { 254 | disabled: false, 255 | 256 | // callbacks 257 | create: null 258 | }, 259 | _createWidget: function( options, element ) { 260 | element = $( element || this.defaultElement || this )[ 0 ]; 261 | this.element = $( element ); 262 | this.uuid = widget_uuid++; 263 | this.eventNamespace = "." + this.widgetName + this.uuid; 264 | 265 | this.bindings = $(); 266 | this.hoverable = $(); 267 | this.focusable = $(); 268 | 269 | if ( element !== this ) { 270 | $.data( element, this.widgetFullName, this ); 271 | this._on( true, this.element, { 272 | remove: function( event ) { 273 | if ( event.target === element ) { 274 | this.destroy(); 275 | } 276 | } 277 | }); 278 | this.document = $( element.style ? 279 | // element within the document 280 | element.ownerDocument : 281 | // element is window or document 282 | element.document || element ); 283 | this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); 284 | } 285 | 286 | this.options = $.widget.extend( {}, 287 | this.options, 288 | this._getCreateOptions(), 289 | options ); 290 | 291 | this._create(); 292 | this._trigger( "create", null, this._getCreateEventData() ); 293 | this._init(); 294 | }, 295 | _getCreateOptions: $.noop, 296 | _getCreateEventData: $.noop, 297 | _create: $.noop, 298 | _init: $.noop, 299 | 300 | destroy: function() { 301 | this._destroy(); 302 | // we can probably remove the unbind calls in 2.0 303 | // all event bindings should go through this._on() 304 | this.element 305 | .unbind( this.eventNamespace ) 306 | .removeData( this.widgetFullName ) 307 | // support: jquery <1.6.3 308 | // http://bugs.jquery.com/ticket/9413 309 | .removeData( $.camelCase( this.widgetFullName ) ); 310 | this.widget() 311 | .unbind( this.eventNamespace ) 312 | .removeAttr( "aria-disabled" ) 313 | .removeClass( 314 | this.widgetFullName + "-disabled " + 315 | "ui-state-disabled" ); 316 | 317 | // clean up events and states 318 | this.bindings.unbind( this.eventNamespace ); 319 | this.hoverable.removeClass( "ui-state-hover" ); 320 | this.focusable.removeClass( "ui-state-focus" ); 321 | }, 322 | _destroy: $.noop, 323 | 324 | widget: function() { 325 | return this.element; 326 | }, 327 | 328 | option: function( key, value ) { 329 | var options = key, 330 | parts, 331 | curOption, 332 | i; 333 | 334 | if ( arguments.length === 0 ) { 335 | // don't return a reference to the internal hash 336 | return $.widget.extend( {}, this.options ); 337 | } 338 | 339 | if ( typeof key === "string" ) { 340 | // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } 341 | options = {}; 342 | parts = key.split( "." ); 343 | key = parts.shift(); 344 | if ( parts.length ) { 345 | curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); 346 | for ( i = 0; i < parts.length - 1; i++ ) { 347 | curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; 348 | curOption = curOption[ parts[ i ] ]; 349 | } 350 | key = parts.pop(); 351 | if ( arguments.length === 1 ) { 352 | return curOption[ key ] === undefined ? null : curOption[ key ]; 353 | } 354 | curOption[ key ] = value; 355 | } else { 356 | if ( arguments.length === 1 ) { 357 | return this.options[ key ] === undefined ? null : this.options[ key ]; 358 | } 359 | options[ key ] = value; 360 | } 361 | } 362 | 363 | this._setOptions( options ); 364 | 365 | return this; 366 | }, 367 | _setOptions: function( options ) { 368 | var key; 369 | 370 | for ( key in options ) { 371 | this._setOption( key, options[ key ] ); 372 | } 373 | 374 | return this; 375 | }, 376 | _setOption: function( key, value ) { 377 | this.options[ key ] = value; 378 | 379 | if ( key === "disabled" ) { 380 | this.widget() 381 | .toggleClass( this.widgetFullName + "-disabled", !!value ); 382 | 383 | // If the widget is becoming disabled, then nothing is interactive 384 | if ( value ) { 385 | this.hoverable.removeClass( "ui-state-hover" ); 386 | this.focusable.removeClass( "ui-state-focus" ); 387 | } 388 | } 389 | 390 | return this; 391 | }, 392 | 393 | enable: function() { 394 | return this._setOptions({ disabled: false }); 395 | }, 396 | disable: function() { 397 | return this._setOptions({ disabled: true }); 398 | }, 399 | 400 | _on: function( suppressDisabledCheck, element, handlers ) { 401 | var delegateElement, 402 | instance = this; 403 | 404 | // no suppressDisabledCheck flag, shuffle arguments 405 | if ( typeof suppressDisabledCheck !== "boolean" ) { 406 | handlers = element; 407 | element = suppressDisabledCheck; 408 | suppressDisabledCheck = false; 409 | } 410 | 411 | // no element argument, shuffle and use this.element 412 | if ( !handlers ) { 413 | handlers = element; 414 | element = this.element; 415 | delegateElement = this.widget(); 416 | } else { 417 | element = delegateElement = $( element ); 418 | this.bindings = this.bindings.add( element ); 419 | } 420 | 421 | $.each( handlers, function( event, handler ) { 422 | function handlerProxy() { 423 | // allow widgets to customize the disabled handling 424 | // - disabled as an array instead of boolean 425 | // - disabled class as method for disabling individual parts 426 | if ( !suppressDisabledCheck && 427 | ( instance.options.disabled === true || 428 | $( this ).hasClass( "ui-state-disabled" ) ) ) { 429 | return; 430 | } 431 | return ( typeof handler === "string" ? instance[ handler ] : handler ) 432 | .apply( instance, arguments ); 433 | } 434 | 435 | // copy the guid so direct unbinding works 436 | if ( typeof handler !== "string" ) { 437 | handlerProxy.guid = handler.guid = 438 | handler.guid || handlerProxy.guid || $.guid++; 439 | } 440 | 441 | var match = event.match( /^([\w:-]*)\s*(.*)$/ ), 442 | eventName = match[1] + instance.eventNamespace, 443 | selector = match[2]; 444 | if ( selector ) { 445 | delegateElement.delegate( selector, eventName, handlerProxy ); 446 | } else { 447 | element.bind( eventName, handlerProxy ); 448 | } 449 | }); 450 | }, 451 | 452 | _off: function( element, eventName ) { 453 | eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + 454 | this.eventNamespace; 455 | element.unbind( eventName ).undelegate( eventName ); 456 | 457 | // Clear the stack to avoid memory leaks (#10056) 458 | this.bindings = $( this.bindings.not( element ).get() ); 459 | this.focusable = $( this.focusable.not( element ).get() ); 460 | this.hoverable = $( this.hoverable.not( element ).get() ); 461 | }, 462 | 463 | _delay: function( handler, delay ) { 464 | function handlerProxy() { 465 | return ( typeof handler === "string" ? instance[ handler ] : handler ) 466 | .apply( instance, arguments ); 467 | } 468 | var instance = this; 469 | return setTimeout( handlerProxy, delay || 0 ); 470 | }, 471 | 472 | _hoverable: function( element ) { 473 | this.hoverable = this.hoverable.add( element ); 474 | this._on( element, { 475 | mouseenter: function( event ) { 476 | $( event.currentTarget ).addClass( "ui-state-hover" ); 477 | }, 478 | mouseleave: function( event ) { 479 | $( event.currentTarget ).removeClass( "ui-state-hover" ); 480 | } 481 | }); 482 | }, 483 | 484 | _focusable: function( element ) { 485 | this.focusable = this.focusable.add( element ); 486 | this._on( element, { 487 | focusin: function( event ) { 488 | $( event.currentTarget ).addClass( "ui-state-focus" ); 489 | }, 490 | focusout: function( event ) { 491 | $( event.currentTarget ).removeClass( "ui-state-focus" ); 492 | } 493 | }); 494 | }, 495 | 496 | _trigger: function( type, event, data ) { 497 | var prop, orig, 498 | callback = this.options[ type ]; 499 | 500 | data = data || {}; 501 | event = $.Event( event ); 502 | event.type = ( type === this.widgetEventPrefix ? 503 | type : 504 | this.widgetEventPrefix + type ).toLowerCase(); 505 | // the original event may come from any element 506 | // so we need to reset the target on the new event 507 | event.target = this.element[ 0 ]; 508 | 509 | // copy original event properties over to the new event 510 | orig = event.originalEvent; 511 | if ( orig ) { 512 | for ( prop in orig ) { 513 | if ( !( prop in event ) ) { 514 | event[ prop ] = orig[ prop ]; 515 | } 516 | } 517 | } 518 | 519 | this.element.trigger( event, data ); 520 | return !( $.isFunction( callback ) && 521 | callback.apply( this.element[0], [ event ].concat( data ) ) === false || 522 | event.isDefaultPrevented() ); 523 | } 524 | }; 525 | 526 | $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { 527 | $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { 528 | if ( typeof options === "string" ) { 529 | options = { effect: options }; 530 | } 531 | var hasOptions, 532 | effectName = !options ? 533 | method : 534 | options === true || typeof options === "number" ? 535 | defaultEffect : 536 | options.effect || defaultEffect; 537 | options = options || {}; 538 | if ( typeof options === "number" ) { 539 | options = { duration: options }; 540 | } 541 | hasOptions = !$.isEmptyObject( options ); 542 | options.complete = callback; 543 | if ( options.delay ) { 544 | element.delay( options.delay ); 545 | } 546 | if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { 547 | element[ method ]( options ); 548 | } else if ( effectName !== method && element[ effectName ] ) { 549 | element[ effectName ]( options.duration, options.easing, callback ); 550 | } else { 551 | element.queue(function( next ) { 552 | $( this )[ method ](); 553 | if ( callback ) { 554 | callback.call( element[ 0 ] ); 555 | } 556 | next(); 557 | }); 558 | } 559 | }; 560 | }); 561 | 562 | var widget = $.widget; 563 | 564 | 565 | 566 | })); 567 | -------------------------------------------------------------------------------- /app/docs/slate/source/javascripts/lib/jquery.tocify.js: -------------------------------------------------------------------------------- 1 | //= require ./jquery_ui 2 | /* jquery Tocify - v1.8.0 - 2013-09-16 3 | * http://www.gregfranko.com/jquery.tocify.js/ 4 | * Copyright (c) 2013 Greg Franko; Licensed MIT 5 | * Modified lightly by Robert Lord to fix a bug I found, 6 | * and also so it adds ids to headers 7 | * also because I want height caching, since the 8 | * height lookup for h1s and h2s was causing serious 9 | * lag spikes below 30 fps */ 10 | 11 | // Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic. I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE. 12 | (function(tocify) { 13 | 14 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 15 | "use strict"; 16 | 17 | // Calls the second IIFE and locally passes in the global jQuery, window, and document objects 18 | tocify(window.jQuery, window, document); 19 | 20 | } 21 | 22 | // Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable. The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set. All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript. 23 | (function($, window, document, undefined) { 24 | 25 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 26 | "use strict"; 27 | 28 | var tocClassName = "tocify", 29 | tocClass = "." + tocClassName, 30 | tocFocusClassName = "tocify-focus", 31 | tocHoverClassName = "tocify-hover", 32 | hideTocClassName = "tocify-hide", 33 | hideTocClass = "." + hideTocClassName, 34 | headerClassName = "tocify-header", 35 | headerClass = "." + headerClassName, 36 | subheaderClassName = "tocify-subheader", 37 | subheaderClass = "." + subheaderClassName, 38 | itemClassName = "tocify-item", 39 | itemClass = "." + itemClassName, 40 | extendPageClassName = "tocify-extend-page", 41 | extendPageClass = "." + extendPageClassName; 42 | 43 | // Calling the jQueryUI Widget Factory Method 44 | $.widget("toc.tocify", { 45 | 46 | //Plugin version 47 | version: "1.8.0", 48 | 49 | // These options will be used as defaults 50 | options: { 51 | 52 | // **context**: Accepts String: Any jQuery selector 53 | // The container element that holds all of the elements used to generate the table of contents 54 | context: "body", 55 | 56 | // **ignoreSelector**: Accepts String: Any jQuery selector 57 | // A selector to any element that would be matched by selectors that you wish to be ignored 58 | ignoreSelector: null, 59 | 60 | // **selectors**: Accepts an Array of Strings: Any jQuery selectors 61 | // The element's used to generate the table of contents. The order is very important since it will determine the table of content's nesting structure 62 | selectors: "h1, h2, h3", 63 | 64 | // **showAndHide**: Accepts a boolean: true or false 65 | // Used to determine if elements should be shown and hidden 66 | showAndHide: true, 67 | 68 | // **showEffect**: Accepts String: "none", "fadeIn", "show", or "slideDown" 69 | // Used to display any of the table of contents nested items 70 | showEffect: "slideDown", 71 | 72 | // **showEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast" 73 | // The time duration of the show animation 74 | showEffectSpeed: "medium", 75 | 76 | // **hideEffect**: Accepts String: "none", "fadeOut", "hide", or "slideUp" 77 | // Used to hide any of the table of contents nested items 78 | hideEffect: "slideUp", 79 | 80 | // **hideEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast" 81 | // The time duration of the hide animation 82 | hideEffectSpeed: "medium", 83 | 84 | // **smoothScroll**: Accepts a boolean: true or false 85 | // Determines if a jQuery animation should be used to scroll to specific table of contents items on the page 86 | smoothScroll: true, 87 | 88 | // **smoothScrollSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast" 89 | // The time duration of the smoothScroll animation 90 | smoothScrollSpeed: "medium", 91 | 92 | // **scrollTo**: Accepts Number (pixels) 93 | // The amount of space between the top of page and the selected table of contents item after the page has been scrolled 94 | scrollTo: 0, 95 | 96 | // **showAndHideOnScroll**: Accepts a boolean: true or false 97 | // Determines if table of contents nested items should be shown and hidden while scrolling 98 | showAndHideOnScroll: true, 99 | 100 | // **highlightOnScroll**: Accepts a boolean: true or false 101 | // Determines if table of contents nested items should be highlighted (set to a different color) while scrolling 102 | highlightOnScroll: true, 103 | 104 | // **highlightOffset**: Accepts a number 105 | // The offset distance in pixels to trigger the next active table of contents item 106 | highlightOffset: 40, 107 | 108 | // **theme**: Accepts a string: "bootstrap", "jqueryui", or "none" 109 | // Determines if Twitter Bootstrap, jQueryUI, or Tocify classes should be added to the table of contents 110 | theme: "bootstrap", 111 | 112 | // **extendPage**: Accepts a boolean: true or false 113 | // If a user scrolls to the bottom of the page and the page is not tall enough to scroll to the last table of contents item, then the page height is increased 114 | extendPage: true, 115 | 116 | // **extendPageOffset**: Accepts a number: pixels 117 | // How close to the bottom of the page a user must scroll before the page is extended 118 | extendPageOffset: 100, 119 | 120 | // **history**: Accepts a boolean: true or false 121 | // Adds a hash to the page url to maintain history 122 | history: true, 123 | 124 | // **scrollHistory**: Accepts a boolean: true or false 125 | // Adds a hash to the page url, to maintain history, when scrolling to a TOC item 126 | scrollHistory: false, 127 | 128 | // **hashGenerator**: How the hash value (the anchor segment of the URL, following the 129 | // # character) will be generated. 130 | // 131 | // "compact" (default) - #CompressesEverythingTogether 132 | // "pretty" - #looks-like-a-nice-url-and-is-easily-readable 133 | // function(text, element){} - Your own hash generation function that accepts the text as an 134 | // argument, and returns the hash value. 135 | hashGenerator: "compact", 136 | 137 | // **highlightDefault**: Accepts a boolean: true or false 138 | // Set's the first TOC item as active if no other TOC item is active. 139 | highlightDefault: true 140 | 141 | }, 142 | 143 | // _Create 144 | // ------- 145 | // Constructs the plugin. Only called once. 146 | _create: function() { 147 | 148 | var self = this; 149 | 150 | self.tocifyWrapper = $('.tocify-wrapper'); 151 | self.extendPageScroll = true; 152 | 153 | // Internal array that keeps track of all TOC items (Helps to recognize if there are duplicate TOC item strings) 154 | self.items = []; 155 | 156 | // Generates the HTML for the dynamic table of contents 157 | self._generateToc(); 158 | 159 | // Caches heights and anchors 160 | self.cachedHeights = [], 161 | self.cachedAnchors = []; 162 | 163 | // Adds CSS classes to the newly generated table of contents HTML 164 | self._addCSSClasses(); 165 | 166 | self.webkit = (function() { 167 | 168 | for(var prop in window) { 169 | 170 | if(prop) { 171 | 172 | if(prop.toLowerCase().indexOf("webkit") !== -1) { 173 | 174 | return true; 175 | 176 | } 177 | 178 | } 179 | 180 | } 181 | 182 | return false; 183 | 184 | }()); 185 | 186 | // Adds jQuery event handlers to the newly generated table of contents 187 | self._setEventHandlers(); 188 | 189 | // Binding to the Window load event to make sure the correct scrollTop is calculated 190 | $(window).load(function() { 191 | 192 | // Sets the active TOC item 193 | self._setActiveElement(true); 194 | 195 | // Once all animations on the page are complete, this callback function will be called 196 | $("html, body").promise().done(function() { 197 | 198 | setTimeout(function() { 199 | 200 | self.extendPageScroll = false; 201 | 202 | },0); 203 | 204 | }); 205 | 206 | }); 207 | 208 | }, 209 | 210 | // _generateToc 211 | // ------------ 212 | // Generates the HTML for the dynamic table of contents 213 | _generateToc: function() { 214 | 215 | // _Local variables_ 216 | 217 | // Stores the plugin context in the self variable 218 | var self = this, 219 | 220 | // All of the HTML tags found within the context provided (i.e. body) that match the top level jQuery selector above 221 | firstElem, 222 | 223 | // Instantiated variable that will store the top level newly created unordered list DOM element 224 | ul, 225 | ignoreSelector = self.options.ignoreSelector; 226 | 227 | // If the selectors option has a comma within the string 228 | if(this.options.selectors.indexOf(",") !== -1) { 229 | 230 | // Grabs the first selector from the string 231 | firstElem = $(this.options.context).find(this.options.selectors.replace(/ /g,"").substr(0, this.options.selectors.indexOf(","))); 232 | 233 | } 234 | 235 | // If the selectors option does not have a comman within the string 236 | else { 237 | 238 | // Grabs the first selector from the string and makes sure there are no spaces 239 | firstElem = $(this.options.context).find(this.options.selectors.replace(/ /g,"")); 240 | 241 | } 242 | 243 | if(!firstElem.length) { 244 | 245 | self.element.addClass(hideTocClassName); 246 | 247 | return; 248 | 249 | } 250 | 251 | self.element.addClass(tocClassName); 252 | 253 | // Loops through each top level selector 254 | firstElem.each(function(index) { 255 | 256 | //If the element matches the ignoreSelector then we skip it 257 | if($(this).is(ignoreSelector)) { 258 | return; 259 | } 260 | 261 | // Creates an unordered list HTML element and adds a dynamic ID and standard class name 262 | ul = $("