├── .dockerignore ├── source ├── fonts │ ├── slate.eot │ ├── slate.ttf │ ├── slate.woff │ ├── slate.woff2 │ └── slate.svg ├── images │ ├── logo.png │ └── navbar.png ├── javascripts │ ├── all_nosearch.js │ ├── all.js │ ├── app │ │ ├── _toc.js │ │ ├── _search.js │ │ └── _lang.js │ └── lib │ │ ├── _jquery.highlight.js │ │ ├── _energize.js │ │ ├── _imagesloaded.min.js │ │ ├── _jquery_ui.js │ │ ├── _jquery.tocify.js │ │ └── _lunr.js ├── stylesheets │ ├── _icon-font.scss │ ├── print.css.scss │ ├── _variables.scss │ ├── _normalize.scss │ └── screen.css.scss ├── includes │ └── _errors.md ├── layouts │ └── layout.erb └── index.html.md ├── run_slate.sh ├── .travis.yml ├── Dockerfile ├── Gemfile ├── .gitignore ├── .github ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── LICENSE ├── config.rb ├── Vagrantfile ├── CHANGELOG.md ├── Gemfile.lock ├── font-selection.json ├── README.md └── deploy.sh /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | source 3 | 4 | -------------------------------------------------------------------------------- /source/fonts/slate.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InsightDataScience/slate/master/source/fonts/slate.eot -------------------------------------------------------------------------------- /source/fonts/slate.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InsightDataScience/slate/master/source/fonts/slate.ttf -------------------------------------------------------------------------------- /source/fonts/slate.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InsightDataScience/slate/master/source/fonts/slate.woff -------------------------------------------------------------------------------- /source/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InsightDataScience/slate/master/source/images/logo.png -------------------------------------------------------------------------------- /source/fonts/slate.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InsightDataScience/slate/master/source/fonts/slate.woff2 -------------------------------------------------------------------------------- /source/images/navbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InsightDataScience/slate/master/source/images/navbar.png -------------------------------------------------------------------------------- /source/javascripts/all_nosearch.js: -------------------------------------------------------------------------------- 1 | //= require ./lib/_energize 2 | //= require ./app/_lang 3 | //= require ./app/_toc 4 | -------------------------------------------------------------------------------- /run_slate.sh: -------------------------------------------------------------------------------- 1 | docker run --rm -p 4567:4567 -v /Users/AustinOuyang/dpl/slate/source:/usr/src/app/source --name slate slate 2 | -------------------------------------------------------------------------------- /source/javascripts/all.js: -------------------------------------------------------------------------------- 1 | //= require ./lib/_energize 2 | //= require ./app/_lang 3 | //= require ./app/_search 4 | //= require ./app/_toc 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: ruby 4 | 5 | rvm: 6 | - 2.0.0 7 | - 2.1.0 8 | 9 | cache: bundler 10 | script: bundle exec middleman build 11 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:onbuild 2 | MAINTAINER Adrian Perez 3 | VOLUME /usr/src/app/source 4 | 5 | RUN apt-get update && apt-get install -y nodejs \ 6 | && apt-get clean && rm -rf /var/lib/apt/lists/* 7 | 8 | CMD ["bundle", "exec", "middleman", "server", "--force-polling"] 9 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Middleman 4 | gem 'middleman', '~>4.0.0' 5 | gem 'middleman-gh-pages', '~> 0.0.3' 6 | gem 'middleman-syntax', '~> 2.1.0' 7 | gem 'middleman-autoprefixer', '~> 2.7.0' 8 | gem "middleman-sprockets", "~> 4.0.0.rc" 9 | gem 'rouge', '~> 1.10.1' 10 | gem 'redcarpet', '~> 3.3.2' 11 | -------------------------------------------------------------------------------- /.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 | .vagrant 18 | .sass-cache 19 | 20 | # YARD artifacts 21 | .yardoc 22 | _yardoc 23 | doc/ 24 | .idea/ 25 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Make sure you've checked off all these things before submitting: 2 | 3 | - [ ] This pull request isn't for a company's fork, it's intended for the upstream Slate shared by everybody. 4 | - [ ] This pull request is submitted to the `dev` branch. 5 | - [ ] If it makes frontend changes, this pull request has been tested in the latest version of Firefox, Chrome, IE, and Safari. 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | If this is a question or feature request, make sure to: 2 | 3 | - [ ] The title starts with `Question:` or `Feature:`. 4 | 5 | If this is an bug report, not a question, make sure to: 6 | 7 | - [ ] I'm not running Windows (which is unsupported), or if I am, I can confirm this issue appears on another platform, or Vagrant. 8 | - [ ] This issue appears in the latest `dev` branch. 9 | - [ ] I've included my browser and Ruby version in this issue. 10 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /source/stylesheets/_icon-font.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'slate'; 3 | src:font-url('slate.eot?-syv14m'); 4 | src:font-url('slate.eot?#iefix-syv14m') format('embedded-opentype'), 5 | font-url('slate.woff2?-syv14m') format('woff2'), 6 | font-url('slate.woff?-syv14m') format('woff'), 7 | font-url('slate.ttf?-syv14m') format('truetype'), 8 | font-url('slate.svg?-syv14m#slate') format('svg'); 9 | font-weight: normal; 10 | font-style: normal; 11 | } 12 | 13 | %icon { 14 | font-family: 'slate'; 15 | speak: none; 16 | font-style: normal; 17 | font-weight: normal; 18 | font-variant: normal; 19 | text-transform: none; 20 | line-height: 1; 21 | } 22 | 23 | %icon-exclamation-sign { 24 | @extend %icon; 25 | content: "\e600"; 26 | } 27 | %icon-info-sign { 28 | @extend %icon; 29 | content: "\e602"; 30 | } 31 | %icon-ok-sign { 32 | @extend %icon; 33 | content: "\e606"; 34 | } 35 | %icon-search { 36 | @extend %icon; 37 | content: "\e607"; 38 | } 39 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | activate :autoprefixer do |config| 22 | config.browsers = ['last 2 version', 'Firefox ESR'] 23 | config.cascade = false 24 | config.inline = true 25 | end 26 | 27 | # Github pages require relative links 28 | activate :relative_assets 29 | set :relative_links, true 30 | 31 | # Build Configuration 32 | configure :build do 33 | # If you're having trouble with Middleman hanging, commenting 34 | # out the following two lines has been known to help 35 | activate :minify_css 36 | activate :minify_javascript 37 | # activate :relative_assets 38 | # activate :asset_hash 39 | # activate :gzip 40 | end 41 | 42 | # Deploy Configuration 43 | # If you want Middleman to listen on a different port, you can set that below 44 | set :port, 4567 45 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | Vagrant.configure(2) do |config| 2 | config.vm.box = "ubuntu/trusty64" 3 | config.vm.network :forwarded_port, guest: 4567, host: 4567 4 | 5 | config.vm.provision "bootstrap", 6 | type: "shell", 7 | inline: <<-SHELL 8 | sudo apt-get update 9 | sudo apt-get install -yq ruby2.0 ruby2.0-dev pkg-config build-essential nodejs git libxml2-dev libxslt-dev 10 | sudo apt-get autoremove -yq 11 | gem2.0 install --no-ri --no-rdoc bundler 12 | SHELL 13 | 14 | # add the local user git config to the vm 15 | config.vm.provision "file", source: "~/.gitconfig", destination: ".gitconfig" 16 | 17 | config.vm.provision "install", 18 | type: "shell", 19 | privileged: false, 20 | inline: <<-SHELL 21 | echo "==============================================" 22 | echo "Installing app dependencies" 23 | cd /vagrant 24 | bundle config build.nokogiri --use-system-libraries 25 | bundle install 26 | SHELL 27 | 28 | config.vm.provision "run", 29 | type: "shell", 30 | privileged: false, 31 | run: "always", 32 | inline: <<-SHELL 33 | echo "==============================================" 34 | echo "Starting up middleman at http://localhost:4567" 35 | echo "If it does not come up, check the ~/middleman.log file for any error messages" 36 | cd /vagrant 37 | bundle exec middleman server --force-polling -l 1 &> ~/middleman.log & 38 | SHELL 39 | end 40 | -------------------------------------------------------------------------------- /source/javascripts/app/_toc.js: -------------------------------------------------------------------------------- 1 | //= require ../lib/_jquery 2 | //= require ../lib/_jquery_ui 3 | //= require ../lib/_jquery.tocify 4 | //= require ../lib/_imagesloaded.min 5 | (function (global) { 6 | 'use strict'; 7 | 8 | var closeToc = function() { 9 | $(".tocify-wrapper").removeClass('open'); 10 | $("#nav-button").removeClass('open'); 11 | }; 12 | 13 | var makeToc = function() { 14 | global.toc = $("#toc").tocify({ 15 | selectors: 'h1, h2', 16 | extendPage: false, 17 | theme: 'none', 18 | smoothScroll: false, 19 | showEffectSpeed: 0, 20 | hideEffectSpeed: 180, 21 | ignoreSelector: '.toc-ignore', 22 | highlightOffset: 60, 23 | scrollTo: -1, 24 | scrollHistory: true, 25 | hashGenerator: function (text, element) { 26 | return element.prop('id'); 27 | } 28 | }).data('toc-tocify'); 29 | 30 | $("#nav-button").click(function() { 31 | $(".tocify-wrapper").toggleClass('open'); 32 | $("#nav-button").toggleClass('open'); 33 | return false; 34 | }); 35 | 36 | $(".page-wrapper").click(closeToc); 37 | $(".tocify-item").click(closeToc); 38 | }; 39 | 40 | // Hack to make already open sections to start opened, 41 | // instead of displaying an ugly animation 42 | function animate() { 43 | setTimeout(function() { 44 | toc.setOption('showEffectSpeed', 180); 45 | }, 50); 46 | } 47 | 48 | $(function() { 49 | makeToc(); 50 | animate(); 51 | setupLanguages($('body').data('languages')); 52 | $('.content').imagesLoaded( function() { 53 | global.toc.calculateHeights(); 54 | }); 55 | }); 56 | })(window); 57 | 58 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Version 1.3.3 4 | 5 | *June 11, 2016* 6 | 7 | Documentation and example changes. 8 | 9 | ## Version 1.3.2 10 | 11 | *February 3, 2016* 12 | 13 | A small bugfix for slightly incorrect background colors on code samples in some cases. 14 | 15 | ## Version 1.3.1 16 | 17 | *January 31, 2016* 18 | 19 | A small bugfix for incorrect whitespace in code blocks. 20 | 21 | ## Version 1.3 22 | 23 | *January 27, 2016* 24 | 25 | We've upgraded Middleman and a number of other dependencies, which should fix quite a few bugs. 26 | 27 | Instead of `rake build` and `rake deploy`, you should now run `bundle exec middleman build --clean` to build your server, and `./deploy.sh` to deploy it to Github Pages. 28 | 29 | ## Version 1.2 30 | 31 | *June 20, 2015* 32 | 33 | **Fixes:** 34 | 35 | - Remove crash on invalid languages 36 | - Update Tocify to scroll to the highlighted header in the Table of Contents 37 | - Fix variable leak and update search algorithms 38 | - Update Python examples to be valid Python 39 | - Update gems 40 | - More misc. bugfixes of Javascript errors 41 | - Add Dockerfile 42 | - Remove unused gems 43 | - Optimize images, fonts, and generated asset files 44 | - Add chinese font support 45 | - Remove RedCarpet header ID patch 46 | - Update language tabs to not disturb existing query strings 47 | 48 | ## Version 1.1 49 | 50 | *July 27, 2014* 51 | 52 | **Fixes:** 53 | 54 | - Finally, a fix for the redcarpet upgrade bug 55 | 56 | ## Version 1.0 57 | 58 | *July 2, 2014* 59 | 60 | [View Issues](https://github.com/tripit/slate/issues?milestone=1&state=closed) 61 | 62 | **Features:** 63 | 64 | - Responsive designs for phones and tablets 65 | - Started tagging versions 66 | 67 | **Fixes:** 68 | 69 | - Fixed 'unrecognized expression' error 70 | - Fixed #undefined hash bug 71 | - Fixed bug where the current language tab would be unselected 72 | - Fixed bug where tocify wouldn't highlight the current section while searching 73 | - Fixed bug where ids of header tags would have special characters that caused problems 74 | - Updated layout so that pages with disabled search wouldn't load search.js 75 | - Cleaned up Javascript 76 | -------------------------------------------------------------------------------- /source/javascripts/app/_search.js: -------------------------------------------------------------------------------- 1 | //= require ../lib/_lunr 2 | //= require ../lib/_jquery 3 | //= require ../lib/_jquery.highlight 4 | (function () { 5 | 'use strict'; 6 | 7 | var content, searchResults; 8 | var highlightOpts = { element: 'span', className: 'search-highlight' }; 9 | 10 | var index = new lunr.Index(); 11 | 12 | index.ref('id'); 13 | index.field('title', { boost: 10 }); 14 | index.field('body'); 15 | index.pipeline.add(lunr.trimmer, lunr.stopWordFilter); 16 | 17 | $(populate); 18 | $(bind); 19 | 20 | function populate() { 21 | $('h1, h2').each(function() { 22 | var title = $(this); 23 | var body = title.nextUntil('h1, h2'); 24 | index.add({ 25 | id: title.prop('id'), 26 | title: title.text(), 27 | body: body.text() 28 | }); 29 | }); 30 | } 31 | 32 | function bind() { 33 | content = $('.content'); 34 | searchResults = $('.search-results'); 35 | 36 | $('#input-search').on('keyup', search); 37 | } 38 | 39 | function search(event) { 40 | unhighlight(); 41 | searchResults.addClass('visible'); 42 | 43 | // ESC clears the field 44 | if (event.keyCode === 27) this.value = ''; 45 | 46 | if (this.value) { 47 | var results = index.search(this.value).filter(function(r) { 48 | return r.score > 0.0001; 49 | }); 50 | 51 | if (results.length) { 52 | searchResults.empty(); 53 | $.each(results, function (index, result) { 54 | var elem = document.getElementById(result.ref); 55 | searchResults.append("
  • " + $(elem).text() + "
  • "); 56 | }); 57 | highlight.call(this); 58 | } else { 59 | searchResults.html('
  • '); 60 | $('.search-results li').text('No Results Found for "' + this.value + '"'); 61 | } 62 | } else { 63 | unhighlight(); 64 | searchResults.removeClass('visible'); 65 | } 66 | } 67 | 68 | function highlight() { 69 | if (this.value) content.highlight(this.value, highlightOpts); 70 | } 71 | 72 | function unhighlight() { 73 | content.unhighlight(highlightOpts); 74 | } 75 | })(); 76 | -------------------------------------------------------------------------------- /source/fonts/slate.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /source/stylesheets/print.css.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @import 'normalize'; 3 | @import 'variables'; 4 | @import 'icon-font'; 5 | 6 | /* 7 | Copyright 2008-2013 Concur Technologies, Inc. 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); you may 10 | not use this file except in compliance with the License. You may obtain 11 | a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 17 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 18 | License for the specific language governing permissions and limitations 19 | under the License. 20 | */ 21 | 22 | $print-color: #999; 23 | $print-color-light: #ccc; 24 | $print-font-size: 12px; 25 | 26 | body { 27 | @extend %default-font; 28 | } 29 | 30 | .tocify, .toc-footer, .lang-selector, .search, #nav-button { 31 | display: none; 32 | } 33 | 34 | .tocify-wrapper>img { 35 | margin: 0 auto; 36 | display: block; 37 | } 38 | 39 | .content { 40 | font-size: 12px; 41 | 42 | pre, code { 43 | @extend %code-font; 44 | @extend %break-words; 45 | border: 1px solid $print-color; 46 | border-radius: 5px; 47 | font-size: 0.8em; 48 | } 49 | 50 | pre { 51 | code { 52 | border: 0; 53 | } 54 | } 55 | 56 | pre { 57 | padding: 1.3em; 58 | } 59 | 60 | code { 61 | padding: 0.2em; 62 | } 63 | 64 | table { 65 | border: 1px solid $print-color; 66 | tr { 67 | border-bottom: 1px solid $print-color; 68 | } 69 | td,th { 70 | padding: 0.7em; 71 | } 72 | } 73 | 74 | p { 75 | line-height: 1.5; 76 | } 77 | 78 | a { 79 | text-decoration: none; 80 | color: #000; 81 | } 82 | 83 | h1 { 84 | @extend %header-font; 85 | font-size: 2.5em; 86 | padding-top: 0.5em; 87 | padding-bottom: 0.5em; 88 | margin-top: 1em; 89 | margin-bottom: $h1-margin-bottom; 90 | border: 2px solid $print-color-light; 91 | border-width: 2px 0; 92 | text-align: center; 93 | } 94 | 95 | h2 { 96 | @extend %header-font; 97 | font-size: 1.8em; 98 | margin-top: 2em; 99 | border-top: 2px solid $print-color-light; 100 | padding-top: 0.8em; 101 | } 102 | 103 | h1+h2, h1+div+h2 { 104 | border-top: none; 105 | padding-top: 0; 106 | margin-top: 0; 107 | } 108 | 109 | h3, h4 { 110 | @extend %header-font; 111 | font-size: 0.8em; 112 | margin-top: 1.5em; 113 | margin-bottom: 0.8em; 114 | text-transform: uppercase; 115 | } 116 | 117 | h5, h6 { 118 | text-transform: uppercase; 119 | } 120 | 121 | aside { 122 | padding: 1em; 123 | border: 1px solid $print-color-light; 124 | border-radius: 5px; 125 | margin-top: 1.5em; 126 | margin-bottom: 1.5em; 127 | line-height: 1.6; 128 | } 129 | 130 | aside:before { 131 | vertical-align: middle; 132 | padding-right: 0.5em; 133 | font-size: 14px; 134 | } 135 | 136 | aside.notice:before { 137 | @extend %icon-info-sign; 138 | } 139 | 140 | aside.warning:before { 141 | @extend %icon-exclamation-sign; 142 | } 143 | 144 | aside.success:before { 145 | @extend %icon-ok-sign; 146 | } 147 | } -------------------------------------------------------------------------------- /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 | 28 | <%= stylesheet_link_tag :screen, media: :screen %> 29 | <%= stylesheet_link_tag :print, media: :print %> 30 | <% if current_page.data.search %> 31 | <%= javascript_include_tag "all" %> 32 | <% else %> 33 | <%= javascript_include_tag "all_nosearch" %> 34 | <% end %> 35 | 36 | 37 | 38 | 39 | 40 | NAV 41 | <%= image_tag('navbar.png') %> 42 | 43 | 44 |
    45 | <%= image_tag "logo.png" %> 46 | <% if language_tabs %> 47 |
    48 | <% language_tabs.each do |lang| %> 49 | <% if lang.is_a? Hash %> 50 | <%= lang.values.first %> 51 | <% else %> 52 | <%= lang %> 53 | <% end %> 54 | <% end %> 55 |
    56 | <% end %> 57 | <% if current_page.data.search %> 58 | 61 | 62 | <% end %> 63 |
    64 |
    65 | <% if current_page.data.toc_footers %> 66 | 71 | <% end %> 72 |
    73 |
    74 |
    75 |
    76 | <%= yield %> 77 | <% current_page.data.includes && current_page.data.includes.each do |include| %> 78 | <%= partial "includes/#{include}" %> 79 | <% end %> 80 |
    81 |
    82 | <% if language_tabs %> 83 |
    84 | <% language_tabs.each do |lang| %> 85 | <% if lang.is_a? Hash %> 86 | <%= lang.values.first %> 87 | <% else %> 88 | <%= lang %> 89 | <% end %> 90 | <% end %> 91 |
    92 | <% end %> 93 |
    94 |
    95 | 96 | 97 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | activesupport (4.2.5.1) 5 | i18n (~> 0.7) 6 | json (~> 1.7, >= 1.7.7) 7 | minitest (~> 5.1) 8 | thread_safe (~> 0.3, >= 0.3.4) 9 | tzinfo (~> 1.1) 10 | addressable (2.4.0) 11 | autoprefixer-rails (6.3.1) 12 | execjs 13 | json 14 | backports (3.6.7) 15 | capybara (2.5.0) 16 | mime-types (>= 1.16) 17 | nokogiri (>= 1.3.3) 18 | rack (>= 1.0.0) 19 | rack-test (>= 0.5.4) 20 | xpath (~> 2.0) 21 | coffee-script (2.4.1) 22 | coffee-script-source 23 | execjs 24 | coffee-script-source (1.10.0) 25 | compass-import-once (1.0.5) 26 | sass (>= 3.2, < 3.5) 27 | concurrent-ruby (0.9.2) 28 | contracts (0.12.0) 29 | erubis (2.7.0) 30 | execjs (2.6.0) 31 | fastimage (1.8.1) 32 | addressable (~> 2.3, >= 2.3.5) 33 | ffi (1.9.10) 34 | haml (4.0.7) 35 | tilt 36 | hamster (2.0.0) 37 | concurrent-ruby (~> 0.8) 38 | hashie (3.4.3) 39 | i18n (0.7.0) 40 | json (1.8.3) 41 | kramdown (1.9.0) 42 | listen (3.0.5) 43 | rb-fsevent (>= 0.9.3) 44 | rb-inotify (>= 0.9) 45 | middleman (4.0.0) 46 | coffee-script (~> 2.2) 47 | compass-import-once (= 1.0.5) 48 | haml (>= 4.0.5) 49 | kramdown (~> 1.2) 50 | middleman-cli (= 4.0.0) 51 | middleman-core (= 4.0.0) 52 | sass (>= 3.4.0, < 4.0) 53 | middleman-autoprefixer (2.7.0) 54 | autoprefixer-rails (>= 6.3.1, < 7.0.0) 55 | middleman-core (>= 3.3.3) 56 | middleman-cli (4.0.0) 57 | thor (>= 0.17.0, < 2.0) 58 | middleman-core (4.0.0) 59 | activesupport (~> 4.2) 60 | addressable (~> 2.4.0) 61 | backports (~> 3.6) 62 | bundler (~> 1.1) 63 | capybara (~> 2.5.0) 64 | contracts (~> 0.12.0) 65 | erubis 66 | execjs (~> 2.0) 67 | fastimage (~> 1.8) 68 | hamster (~> 2.0) 69 | hashie (~> 3.4) 70 | i18n (~> 0.7.0) 71 | listen (~> 3.0) 72 | padrino-helpers (~> 0.13.0) 73 | rack (>= 1.4.5, < 2.0) 74 | sass (>= 3.4) 75 | tilt (~> 1.4.1) 76 | uglifier (~> 2.6) 77 | middleman-gh-pages (0.0.3) 78 | rake (> 0.9.3) 79 | middleman-sprockets (4.0.0.rc.1) 80 | middleman-core (>= 4.0.0.rc.1) 81 | sprockets (~> 3.0) 82 | middleman-syntax (2.1.0) 83 | middleman-core (>= 3.2) 84 | rouge (~> 1.0) 85 | mime-types (3.0) 86 | mime-types-data (~> 3.2015) 87 | mime-types-data (3.2015.1120) 88 | mini_portile2 (2.0.0) 89 | minitest (5.8.4) 90 | nokogiri (1.6.7.2) 91 | mini_portile2 (~> 2.0.0.rc2) 92 | padrino-helpers (0.13.1) 93 | i18n (~> 0.6, >= 0.6.7) 94 | padrino-support (= 0.13.1) 95 | tilt (~> 1.4.1) 96 | padrino-support (0.13.1) 97 | activesupport (>= 3.1) 98 | rack (1.6.4) 99 | rack-test (0.6.3) 100 | rack (>= 1.0) 101 | rake (10.4.2) 102 | rb-fsevent (0.9.7) 103 | rb-inotify (0.9.5) 104 | ffi (>= 0.5.0) 105 | redcarpet (3.3.4) 106 | rouge (1.10.1) 107 | sass (3.4.21) 108 | sprockets (3.4.1) 109 | rack (> 1, < 3) 110 | thor (0.19.1) 111 | thread_safe (0.3.5) 112 | tilt (1.4.1) 113 | tzinfo (1.2.2) 114 | thread_safe (~> 0.1) 115 | uglifier (2.7.2) 116 | execjs (>= 0.3.0) 117 | json (>= 1.8.0) 118 | xpath (2.0.0) 119 | nokogiri (~> 1.3) 120 | 121 | PLATFORMS 122 | ruby 123 | 124 | DEPENDENCIES 125 | middleman (~> 4.0.0) 126 | middleman-autoprefixer (~> 2.7.0) 127 | middleman-gh-pages (~> 0.0.3) 128 | middleman-sprockets (~> 4.0.0.rc) 129 | middleman-syntax (~> 2.1.0) 130 | redcarpet (~> 3.3.2) 131 | rouge (~> 1.10.1) 132 | 133 | BUNDLED WITH 134 | 1.10.6 135 | -------------------------------------------------------------------------------- /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, "Microsoft Yahei","微软雅黑", STXihei, "华文细黑", 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 | word-break: break-all; 104 | hyphens: auto; 105 | } 106 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /source/index.html.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: API Reference 3 | 4 | language_tabs: 5 | - shell 6 | - ruby 7 | - python 8 | - javascript 9 | 10 | toc_footers: 11 | - Sign Up for a Developer Key 12 | - Documentation Powered by Slate 13 | 14 | includes: 15 | - errors 16 | 17 | search: true 18 | --- 19 | 20 | # Introduction 21 | 22 | Welcome to the Kittn API! You can use our API to access Kittn API endpoints, which can get information on various cats, kittens, and breeds in our database. 23 | 24 | We have language bindings in Shell, Ruby, and Python! You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right. 25 | 26 | This example API documentation page was created with [Slate](https://github.com/tripit/slate). Feel free to edit it and use it as a base for your own API's documentation. 27 | 28 | # Authentication 29 | 30 | > To authorize, use this code: 31 | 32 | ```ruby 33 | require 'kittn' 34 | 35 | api = Kittn::APIClient.authorize!('meowmeowmeow') 36 | ``` 37 | 38 | ```python 39 | import kittn 40 | 41 | api = kittn.authorize('meowmeowmeow') 42 | ``` 43 | 44 | ```shell 45 | # With shell, you can just pass the correct header with each request 46 | curl "api_endpoint_here" 47 | -H "Authorization: meowmeowmeow" 48 | ``` 49 | 50 | ```javascript 51 | const kittn = require('kittn'); 52 | 53 | let api = kittn.authorize('meowmeowmeow'); 54 | ``` 55 | 56 | > Make sure to replace `meowmeowmeow` with your API key. 57 | 58 | Kittn uses API keys to allow access to the API. You can register a new Kittn API key at our [developer portal](http://example.com/developers). 59 | 60 | Kittn expects for the API key to be included in all API requests to the server in a header that looks like the following: 61 | 62 | `Authorization: meowmeowmeow` 63 | 64 | 67 | 68 | # Kittens 69 | 70 | ## Get All Kittens 71 | 72 | ```ruby 73 | require 'kittn' 74 | 75 | api = Kittn::APIClient.authorize!('meowmeowmeow') 76 | api.kittens.get 77 | ``` 78 | 79 | ```python 80 | import kittn 81 | 82 | api = kittn.authorize('meowmeowmeow') 83 | api.kittens.get() 84 | ``` 85 | 86 | ```shell 87 | curl "http://example.com/api/kittens" 88 | -H "Authorization: meowmeowmeow" 89 | ``` 90 | 91 | ```javascript 92 | const kittn = require('kittn'); 93 | 94 | let api = kittn.authorize('meowmeowmeow'); 95 | let kittens = api.kittens.get(); 96 | ``` 97 | 98 | > The above command returns JSON structured like this: 99 | 100 | ```json 101 | [ 102 | { 103 | "id": 1, 104 | "name": "Fluffums", 105 | "breed": "calico", 106 | "fluffiness": 6, 107 | "cuteness": 7 108 | }, 109 | { 110 | "id": 2, 111 | "name": "Max", 112 | "breed": "unknown", 113 | "fluffiness": 5, 114 | "cuteness": 10 115 | } 116 | ] 117 | ``` 118 | 119 | This endpoint retrieves all kittens. 120 | 121 | ### HTTP Request 122 | 123 | `GET http://example.com/api/kittens` 124 | 125 | ### Query Parameters 126 | 127 | Parameter | Default | Description 128 | --------- | ------- | ----------- 129 | include_cats | false | If set to true, the result will also include cats. 130 | available | true | If set to false, the result will include kittens that have already been adopted. 131 | 132 | 135 | 136 | ## Get a Specific Kitten 137 | 138 | ```ruby 139 | require 'kittn' 140 | 141 | api = Kittn::APIClient.authorize!('meowmeowmeow') 142 | api.kittens.get(2) 143 | ``` 144 | 145 | ```python 146 | import kittn 147 | 148 | api = kittn.authorize('meowmeowmeow') 149 | api.kittens.get(2) 150 | ``` 151 | 152 | ```shell 153 | curl "http://example.com/api/kittens/2" 154 | -H "Authorization: meowmeowmeow" 155 | ``` 156 | 157 | ```javascript 158 | const kittn = require('kittn'); 159 | 160 | let api = kittn.authorize('meowmeowmeow'); 161 | let max = api.kittens.get(2); 162 | ``` 163 | 164 | > The above command returns JSON structured like this: 165 | 166 | ```json 167 | { 168 | "id": 2, 169 | "name": "Max", 170 | "breed": "unknown", 171 | "fluffiness": 5, 172 | "cuteness": 10 173 | } 174 | ``` 175 | 176 | This endpoint retrieves a specific kitten. 177 | 178 | 179 | 180 | ### HTTP Request 181 | 182 | `GET http://example.com/kittens/` 183 | 184 | ### URL Parameters 185 | 186 | Parameter | Description 187 | --------- | ----------- 188 | ID | The ID of the kitten to retrieve 189 | 190 | -------------------------------------------------------------------------------- /font-selection.json: -------------------------------------------------------------------------------- 1 | { 2 | "IcoMoonType": "selection", 3 | "icons": [ 4 | { 5 | "icon": { 6 | "paths": [ 7 | "M438.857 73.143q119.429 0 220.286 58.857t159.714 159.714 58.857 220.286-58.857 220.286-159.714 159.714-220.286 58.857-220.286-58.857-159.714-159.714-58.857-220.286 58.857-220.286 159.714-159.714 220.286-58.857zM512 785.714v-108.571q0-8-5.143-13.429t-12.571-5.429h-109.714q-7.429 0-13.143 5.714t-5.714 13.143v108.571q0 7.429 5.714 13.143t13.143 5.714h109.714q7.429 0 12.571-5.429t5.143-13.429zM510.857 589.143l10.286-354.857q0-6.857-5.714-10.286-5.714-4.571-13.714-4.571h-125.714q-8 0-13.714 4.571-5.714 3.429-5.714 10.286l9.714 354.857q0 5.714 5.714 10t13.714 4.286h105.714q8 0 13.429-4.286t6-10z" 8 | ], 9 | "attrs": [], 10 | "isMulticolor": false, 11 | "tags": [ 12 | "exclamation-circle" 13 | ], 14 | "defaultCode": 61546, 15 | "grid": 14 16 | }, 17 | "attrs": [], 18 | "properties": { 19 | "id": 100, 20 | "order": 4, 21 | "prevSize": 28, 22 | "code": 58880, 23 | "name": "exclamation-sign", 24 | "ligatures": "" 25 | }, 26 | "setIdx": 0, 27 | "iconIdx": 0 28 | }, 29 | { 30 | "icon": { 31 | "paths": [ 32 | "M585.143 786.286v-91.429q0-8-5.143-13.143t-13.143-5.143h-54.857v-292.571q0-8-5.143-13.143t-13.143-5.143h-182.857q-8 0-13.143 5.143t-5.143 13.143v91.429q0 8 5.143 13.143t13.143 5.143h54.857v182.857h-54.857q-8 0-13.143 5.143t-5.143 13.143v91.429q0 8 5.143 13.143t13.143 5.143h256q8 0 13.143-5.143t5.143-13.143zM512 274.286v-91.429q0-8-5.143-13.143t-13.143-5.143h-109.714q-8 0-13.143 5.143t-5.143 13.143v91.429q0 8 5.143 13.143t13.143 5.143h109.714q8 0 13.143-5.143t5.143-13.143zM877.714 512q0 119.429-58.857 220.286t-159.714 159.714-220.286 58.857-220.286-58.857-159.714-159.714-58.857-220.286 58.857-220.286 159.714-159.714 220.286-58.857 220.286 58.857 159.714 159.714 58.857 220.286z" 33 | ], 34 | "attrs": [], 35 | "isMulticolor": false, 36 | "tags": [ 37 | "info-circle" 38 | ], 39 | "defaultCode": 61530, 40 | "grid": 14 41 | }, 42 | "attrs": [], 43 | "properties": { 44 | "id": 85, 45 | "order": 3, 46 | "name": "info-sign", 47 | "prevSize": 28, 48 | "code": 58882 49 | }, 50 | "setIdx": 0, 51 | "iconIdx": 2 52 | }, 53 | { 54 | "icon": { 55 | "paths": [ 56 | "M733.714 419.429q0-16-10.286-26.286l-52-51.429q-10.857-10.857-25.714-10.857t-25.714 10.857l-233.143 232.571-129.143-129.143q-10.857-10.857-25.714-10.857t-25.714 10.857l-52 51.429q-10.286 10.286-10.286 26.286 0 15.429 10.286 25.714l206.857 206.857q10.857 10.857 25.714 10.857 15.429 0 26.286-10.857l310.286-310.286q10.286-10.286 10.286-25.714zM877.714 512q0 119.429-58.857 220.286t-159.714 159.714-220.286 58.857-220.286-58.857-159.714-159.714-58.857-220.286 58.857-220.286 159.714-159.714 220.286-58.857 220.286 58.857 159.714 159.714 58.857 220.286z" 57 | ], 58 | "attrs": [], 59 | "isMulticolor": false, 60 | "tags": [ 61 | "check-circle" 62 | ], 63 | "defaultCode": 61528, 64 | "grid": 14 65 | }, 66 | "attrs": [], 67 | "properties": { 68 | "id": 83, 69 | "order": 9, 70 | "prevSize": 28, 71 | "code": 58886, 72 | "name": "ok-sign" 73 | }, 74 | "setIdx": 0, 75 | "iconIdx": 6 76 | }, 77 | { 78 | "icon": { 79 | "paths": [ 80 | "M658.286 475.429q0-105.714-75.143-180.857t-180.857-75.143-180.857 75.143-75.143 180.857 75.143 180.857 180.857 75.143 180.857-75.143 75.143-180.857zM950.857 950.857q0 29.714-21.714 51.429t-51.429 21.714q-30.857 0-51.429-21.714l-196-195.429q-102.286 70.857-228 70.857-81.714 0-156.286-31.714t-128.571-85.714-85.714-128.571-31.714-156.286 31.714-156.286 85.714-128.571 128.571-85.714 156.286-31.714 156.286 31.714 128.571 85.714 85.714 128.571 31.714 156.286q0 125.714-70.857 228l196 196q21.143 21.143 21.143 51.429z" 81 | ], 82 | "width": 951, 83 | "attrs": [], 84 | "isMulticolor": false, 85 | "tags": [ 86 | "search" 87 | ], 88 | "defaultCode": 61442, 89 | "grid": 14 90 | }, 91 | "attrs": [], 92 | "properties": { 93 | "id": 2, 94 | "order": 1, 95 | "prevSize": 28, 96 | "code": 58887, 97 | "name": "icon-search" 98 | }, 99 | "setIdx": 0, 100 | "iconIdx": 7 101 | } 102 | ], 103 | "height": 1024, 104 | "metadata": { 105 | "name": "slate", 106 | "license": "SIL OFL 1.1" 107 | }, 108 | "preferences": { 109 | "showGlyphs": true, 110 | "showQuickUse": true, 111 | "showQuickUse2": true, 112 | "showSVGs": true, 113 | "fontPref": { 114 | "prefix": "icon-", 115 | "metadata": { 116 | "fontFamily": "slate", 117 | "majorVersion": 1, 118 | "minorVersion": 0, 119 | "description": "Based on FontAwesome", 120 | "license": "SIL OFL 1.1" 121 | }, 122 | "metrics": { 123 | "emSize": 1024, 124 | "baseline": 6.25, 125 | "whitespace": 50 126 | }, 127 | "resetPoint": 58880, 128 | "showSelector": false, 129 | "selector": "class", 130 | "classSelector": ".icon", 131 | "showMetrics": false, 132 | "showMetadata": true, 133 | "showVersion": true, 134 | "ie7": false 135 | }, 136 | "imagePref": { 137 | "prefix": "icon-", 138 | "png": true, 139 | "useClassSelector": true, 140 | "color": 4473924, 141 | "bgColor": 16777215 142 | }, 143 | "historySize": 100, 144 | "showCodes": true, 145 | "gridSize": 16, 146 | "showLiga": false 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /source/javascripts/app/_lang.js: -------------------------------------------------------------------------------- 1 | //= require ../lib/_jquery 2 | 3 | /* 4 | Copyright 2008-2013 Concur Technologies, Inc. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); you may 7 | not use this file except in compliance with the License. You may obtain 8 | a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 | License for the specific language governing permissions and limitations 16 | under the License. 17 | */ 18 | (function (global) { 19 | 'use strict'; 20 | 21 | var languages = []; 22 | 23 | global.setupLanguages = setupLanguages; 24 | global.activateLanguage = activateLanguage; 25 | 26 | function activateLanguage(language) { 27 | if (!language) return; 28 | if (language === "") return; 29 | 30 | $(".lang-selector a").removeClass('active'); 31 | $(".lang-selector a[data-language-name='" + language + "']").addClass('active'); 32 | for (var i=0; i < languages.length; i++) { 33 | $(".highlight." + languages[i]).hide(); 34 | $(".lang-specific." + languages[i]).hide(); 35 | } 36 | $(".highlight." + language).show(); 37 | $(".lang-specific." + language).show(); 38 | 39 | global.toc.calculateHeights(); 40 | 41 | // scroll to the new location of the position 42 | if ($(window.location.hash).get(0)) { 43 | $(window.location.hash).get(0).scrollIntoView(true); 44 | } 45 | } 46 | 47 | // parseURL and stringifyURL are from https://github.com/sindresorhus/query-string 48 | // MIT licensed 49 | // https://github.com/sindresorhus/query-string/blob/7bee64c16f2da1a326579e96977b9227bf6da9e6/license 50 | function parseURL(str) { 51 | if (typeof str !== 'string') { 52 | return {}; 53 | } 54 | 55 | str = str.trim().replace(/^(\?|#|&)/, ''); 56 | 57 | if (!str) { 58 | return {}; 59 | } 60 | 61 | return str.split('&').reduce(function (ret, param) { 62 | var parts = param.replace(/\+/g, ' ').split('='); 63 | var key = parts[0]; 64 | var val = parts[1]; 65 | 66 | key = decodeURIComponent(key); 67 | // missing `=` should be `null`: 68 | // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters 69 | val = val === undefined ? null : decodeURIComponent(val); 70 | 71 | if (!ret.hasOwnProperty(key)) { 72 | ret[key] = val; 73 | } else if (Array.isArray(ret[key])) { 74 | ret[key].push(val); 75 | } else { 76 | ret[key] = [ret[key], val]; 77 | } 78 | 79 | return ret; 80 | }, {}); 81 | }; 82 | 83 | function stringifyURL(obj) { 84 | return obj ? Object.keys(obj).sort().map(function (key) { 85 | var val = obj[key]; 86 | 87 | if (Array.isArray(val)) { 88 | return val.sort().map(function (val2) { 89 | return encodeURIComponent(key) + '=' + encodeURIComponent(val2); 90 | }).join('&'); 91 | } 92 | 93 | return encodeURIComponent(key) + '=' + encodeURIComponent(val); 94 | }).join('&') : ''; 95 | }; 96 | 97 | // gets the language set in the query string 98 | function getLanguageFromQueryString() { 99 | if (location.search.length >= 1) { 100 | var language = parseURL(location.search).language 101 | if (language) { 102 | return language; 103 | } else if (jQuery.inArray(location.search.substr(1), languages) != -1) { 104 | return location.search.substr(1); 105 | } 106 | } 107 | 108 | return false; 109 | } 110 | 111 | // returns a new query string with the new language in it 112 | function generateNewQueryString(language) { 113 | var url = parseURL(location.search); 114 | if (url.language) { 115 | url.language = language; 116 | return stringifyURL(url); 117 | } 118 | return language; 119 | } 120 | 121 | // if a button is clicked, add the state to the history 122 | function pushURL(language) { 123 | if (!history) { return; } 124 | var hash = window.location.hash; 125 | if (hash) { 126 | hash = hash.replace(/^#+/, ''); 127 | } 128 | history.pushState({}, '', '?' + generateNewQueryString(language) + '#' + hash); 129 | 130 | // save language as next default 131 | localStorage.setItem("language", language); 132 | } 133 | 134 | function setupLanguages(l) { 135 | var defaultLanguage = localStorage.getItem("language"); 136 | 137 | languages = l; 138 | 139 | var presetLanguage = getLanguageFromQueryString(); 140 | if (presetLanguage) { 141 | // the language is in the URL, so use that language! 142 | activateLanguage(presetLanguage); 143 | 144 | localStorage.setItem("language", presetLanguage); 145 | } else if ((defaultLanguage !== null) && (jQuery.inArray(defaultLanguage, languages) != -1)) { 146 | // the language was the last selected one saved in localstorage, so use that language! 147 | activateLanguage(defaultLanguage); 148 | } else { 149 | // no language selected, so use the default 150 | activateLanguage(languages[0]); 151 | } 152 | } 153 | 154 | // if we click on a language tab, activate that language 155 | $(function() { 156 | $(".lang-selector a").on("click", function() { 157 | var language = $(this).data("language-name"); 158 | pushURL(language); 159 | activateLanguage(language); 160 | return false; 161 | }); 162 | window.onpopstate = function() { 163 | activateLanguage(getLanguageFromQueryString()); 164 | }; 165 | }); 166 | })(window); 167 | -------------------------------------------------------------------------------- /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 | })(); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

    2 | Slate: API Documentation Generator 3 |
    4 | Build Status 5 |

    6 | 7 |

    Slate helps you create beautiful, intelligent, responsive API documentation.

    8 | 9 |

    Screenshot of Example Documentation created with Slate

    10 | 11 |

    The example above was created with Slate. Check it out at lord.github.io/slate.

    12 | 13 | Features 14 | ------------ 15 | 16 | * **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 in print. 17 | 18 | * **Everything on a single page** — Gone are the days when 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. 19 | 20 | * **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. 21 | 22 | * **Write code samples in multiple languages** — If your API has bindings in multiple programming languages, you can 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. 23 | 24 | * **Out-of-the-box syntax highlighting** for [almost 100 languages](http://rouge.jneen.net/), no configuration required. 25 | 26 | * **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. 27 | 28 | * **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 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 use GitHub, you're also welcome to host your docs elsewhere. 29 | 30 | Getting started with Slate is super easy! Simply fork this repository and 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://lord.github.io/slate). 31 | 32 | Getting Started with Slate 33 | ------------------------------ 34 | 35 | ### Prerequisites 36 | 37 | You're going to need: 38 | 39 | - **Linux or OS X** — Windows may work, but is unsupported. 40 | - **Ruby, version 2.0 or newer** 41 | - **Bundler** — If Ruby is already installed, but the `bundle` command doesn't work, just run `gem install bundler` in a terminal. 42 | 43 | ### Getting Set Up 44 | 45 | 1. Fork this repository on Github. 46 | 2. Clone *your forked repository* (not our original one) to your hard drive with `git clone https://github.com/YOURUSERNAME/slate.git` 47 | 3. `cd slate` 48 | 4. Initialize and start Slate. You can either do this locally, or with Vagrant: 49 | 50 | ```shell 51 | # either run this to run locally 52 | bundle install 53 | bundle exec middleman server 54 | 55 | # OR run this to run with vagrant 56 | vagrant up 57 | ``` 58 | 59 | You can now see the docs at http://localhost:4567. Whoa! That was fast! 60 | 61 | Now that Slate is all set up on your machine, you'll probably want to learn more about [editing Slate markdown](https://github.com/lord/slate/wiki/Markdown-Syntax), or [how to publish your docs](https://github.com/lord/slate/wiki/Deploying-Slate). 62 | 63 | If you'd prefer to use Docker, instructions are available [in the wiki](https://github.com/lord/slate/wiki/Docker). 64 | 65 | Companies Using Slate 66 | --------------------------------- 67 | 68 | * [NASA](https://api.nasa.gov) 69 | * [IBM Cloudant](https://docs.cloudant.com/api.html) 70 | * [Travis-CI](https://docs.travis-ci.com/api/) 71 | * [Mozilla](http://mozilla.github.io/localForage/) 72 | * [Appium](http://appium.io/slate/en/master) 73 | * [Dwolla](https://docs.dwolla.com/) 74 | * [Clearbit](https://clearbit.com/docs) 75 | * [Coinbase](https://developers.coinbase.com/api) 76 | * [Parrot Drones](http://developer.parrot.com/docs/bebop/) 77 | * [Fidor Bank](http://docs.fidor.de/) 78 | 79 | You can view more in [the list on the wiki](https://github.com/lord/slate/wiki/Slate-in-the-Wild). 80 | 81 | Need Help? Found a bug? 82 | -------------------- 83 | 84 | [Submit an issue](https://github.com/lord/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. 85 | 86 | Contributors 87 | -------------------- 88 | 89 | Slate was built by [Robert Lord](https://lord.io) while interning at [TripIt](https://www.tripit.com/). 90 | 91 | Thanks to the following people who have submitted major pull requests: 92 | 93 | - [@chrissrogers](https://github.com/chrissrogers) 94 | - [@bootstraponline](https://github.com/bootstraponline) 95 | - [@realityking](https://github.com/realityking) 96 | - [@cvkef](https://github.com/cvkef) 97 | 98 | Also, thanks to [Sauce Labs](http://saucelabs.com) for helping sponsor the project. 99 | 100 | Special Thanks 101 | -------------------- 102 | - [Middleman](https://github.com/middleman/middleman) 103 | - [jquery.tocify.js](https://github.com/gfranko/jquery.tocify.js) 104 | - [middleman-syntax](https://github.com/middleman/middleman-syntax) 105 | - [middleman-gh-pages](https://github.com/edgecase/middleman-gh-pages) 106 | - [Font Awesome](http://fortawesome.github.io/Font-Awesome/) 107 | -------------------------------------------------------------------------------- /source/javascripts/lib/_imagesloaded.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * imagesLoaded PACKAGED v3.1.8 3 | * JavaScript is all like "You images are done yet or what?" 4 | * MIT License 5 | */ 6 | 7 | (function(){function e(){}function t(e,t){for(var n=e.length;n--;)if(e[n].listener===t)return n;return-1}function n(e){return function(){return this[e].apply(this,arguments)}}var i=e.prototype,r=this,o=r.EventEmitter;i.getListeners=function(e){var t,n,i=this._getEvents();if("object"==typeof e){t={};for(n in i)i.hasOwnProperty(n)&&e.test(n)&&(t[n]=i[n])}else t=i[e]||(i[e]=[]);return t},i.flattenListeners=function(e){var t,n=[];for(t=0;e.length>t;t+=1)n.push(e[t].listener);return n},i.getListenersAsObject=function(e){var t,n=this.getListeners(e);return n instanceof Array&&(t={},t[e]=n),t||n},i.addListener=function(e,n){var i,r=this.getListenersAsObject(e),o="object"==typeof n;for(i in r)r.hasOwnProperty(i)&&-1===t(r[i],n)&&r[i].push(o?n:{listener:n,once:!1});return this},i.on=n("addListener"),i.addOnceListener=function(e,t){return this.addListener(e,{listener:t,once:!0})},i.once=n("addOnceListener"),i.defineEvent=function(e){return this.getListeners(e),this},i.defineEvents=function(e){for(var t=0;e.length>t;t+=1)this.defineEvent(e[t]);return this},i.removeListener=function(e,n){var i,r,o=this.getListenersAsObject(e);for(r in o)o.hasOwnProperty(r)&&(i=t(o[r],n),-1!==i&&o[r].splice(i,1));return this},i.off=n("removeListener"),i.addListeners=function(e,t){return this.manipulateListeners(!1,e,t)},i.removeListeners=function(e,t){return this.manipulateListeners(!0,e,t)},i.manipulateListeners=function(e,t,n){var i,r,o=e?this.removeListener:this.addListener,s=e?this.removeListeners:this.addListeners;if("object"!=typeof t||t instanceof RegExp)for(i=n.length;i--;)o.call(this,t,n[i]);else for(i in t)t.hasOwnProperty(i)&&(r=t[i])&&("function"==typeof r?o.call(this,i,r):s.call(this,i,r));return this},i.removeEvent=function(e){var t,n=typeof e,i=this._getEvents();if("string"===n)delete i[e];else if("object"===n)for(t in i)i.hasOwnProperty(t)&&e.test(t)&&delete i[t];else delete this._events;return this},i.removeAllListeners=n("removeEvent"),i.emitEvent=function(e,t){var n,i,r,o,s=this.getListenersAsObject(e);for(r in s)if(s.hasOwnProperty(r))for(i=s[r].length;i--;)n=s[r][i],n.once===!0&&this.removeListener(e,n.listener),o=n.listener.apply(this,t||[]),o===this._getOnceReturnValue()&&this.removeListener(e,n.listener);return this},i.trigger=n("emitEvent"),i.emit=function(e){var t=Array.prototype.slice.call(arguments,1);return this.emitEvent(e,t)},i.setOnceReturnValue=function(e){return this._onceReturnValue=e,this},i._getOnceReturnValue=function(){return this.hasOwnProperty("_onceReturnValue")?this._onceReturnValue:!0},i._getEvents=function(){return this._events||(this._events={})},e.noConflict=function(){return r.EventEmitter=o,e},"function"==typeof define&&define.amd?define("eventEmitter/EventEmitter",[],function(){return e}):"object"==typeof module&&module.exports?module.exports=e:this.EventEmitter=e}).call(this),function(e){function t(t){var n=e.event;return n.target=n.target||n.srcElement||t,n}var n=document.documentElement,i=function(){};n.addEventListener?i=function(e,t,n){e.addEventListener(t,n,!1)}:n.attachEvent&&(i=function(e,n,i){e[n+i]=i.handleEvent?function(){var n=t(e);i.handleEvent.call(i,n)}:function(){var n=t(e);i.call(e,n)},e.attachEvent("on"+n,e[n+i])});var r=function(){};n.removeEventListener?r=function(e,t,n){e.removeEventListener(t,n,!1)}:n.detachEvent&&(r=function(e,t,n){e.detachEvent("on"+t,e[t+n]);try{delete e[t+n]}catch(i){e[t+n]=void 0}});var o={bind:i,unbind:r};"function"==typeof define&&define.amd?define("eventie/eventie",o):e.eventie=o}(this),function(e,t){"function"==typeof define&&define.amd?define(["eventEmitter/EventEmitter","eventie/eventie"],function(n,i){return t(e,n,i)}):"object"==typeof exports?module.exports=t(e,require("wolfy87-eventemitter"),require("eventie")):e.imagesLoaded=t(e,e.EventEmitter,e.eventie)}(window,function(e,t,n){function i(e,t){for(var n in t)e[n]=t[n];return e}function r(e){return"[object Array]"===d.call(e)}function o(e){var t=[];if(r(e))t=e;else if("number"==typeof e.length)for(var n=0,i=e.length;i>n;n++)t.push(e[n]);else t.push(e);return t}function s(e,t,n){if(!(this instanceof s))return new s(e,t);"string"==typeof e&&(e=document.querySelectorAll(e)),this.elements=o(e),this.options=i({},this.options),"function"==typeof t?n=t:i(this.options,t),n&&this.on("always",n),this.getImages(),a&&(this.jqDeferred=new a.Deferred);var r=this;setTimeout(function(){r.check()})}function f(e){this.img=e}function c(e){this.src=e,v[e]=this}var a=e.jQuery,u=e.console,h=u!==void 0,d=Object.prototype.toString;s.prototype=new t,s.prototype.options={},s.prototype.getImages=function(){this.images=[];for(var e=0,t=this.elements.length;t>e;e++){var n=this.elements[e];"IMG"===n.nodeName&&this.addImage(n);var i=n.nodeType;if(i&&(1===i||9===i||11===i))for(var r=n.querySelectorAll("img"),o=0,s=r.length;s>o;o++){var f=r[o];this.addImage(f)}}},s.prototype.addImage=function(e){var t=new f(e);this.images.push(t)},s.prototype.check=function(){function e(e,r){return t.options.debug&&h&&u.log("confirm",e,r),t.progress(e),n++,n===i&&t.complete(),!0}var t=this,n=0,i=this.images.length;if(this.hasAnyBroken=!1,!i)return this.complete(),void 0;for(var r=0;i>r;r++){var o=this.images[r];o.on("confirm",e),o.check()}},s.prototype.progress=function(e){this.hasAnyBroken=this.hasAnyBroken||!e.isLoaded;var t=this;setTimeout(function(){t.emit("progress",t,e),t.jqDeferred&&t.jqDeferred.notify&&t.jqDeferred.notify(t,e)})},s.prototype.complete=function(){var e=this.hasAnyBroken?"fail":"done";this.isComplete=!0;var t=this;setTimeout(function(){if(t.emit(e,t),t.emit("always",t),t.jqDeferred){var n=t.hasAnyBroken?"reject":"resolve";t.jqDeferred[n](t)}})},a&&(a.fn.imagesLoaded=function(e,t){var n=new s(this,e,t);return n.jqDeferred.promise(a(this))}),f.prototype=new t,f.prototype.check=function(){var e=v[this.img.src]||new c(this.img.src);if(e.isConfirmed)return this.confirm(e.isLoaded,"cached was confirmed"),void 0;if(this.img.complete&&void 0!==this.img.naturalWidth)return this.confirm(0!==this.img.naturalWidth,"naturalWidth"),void 0;var t=this;e.on("confirm",function(e,n){return t.confirm(e.isLoaded,n),!0}),e.check()},f.prototype.confirm=function(e,t){this.isLoaded=e,this.emit("confirm",this,t)};var v={};return c.prototype=new t,c.prototype.check=function(){if(!this.isChecked){var e=new Image;n.bind(e,"load",this),n.bind(e,"error",this),e.src=this.src,this.isChecked=!0}},c.prototype.handleEvent=function(e){var t="on"+e.type;this[t]&&this[t](e)},c.prototype.onload=function(e){this.confirm(!0,"onload"),this.unbindProxyEvents(e)},c.prototype.onerror=function(e){this.confirm(!1,"onerror"),this.unbindProxyEvents(e)},c.prototype.confirm=function(e,t){this.isConfirmed=!0,this.isLoaded=e,this.emit("confirm",this,t)},c.prototype.unbindProxyEvents=function(e){n.unbind(e.target,"load",this),n.unbind(e.target,"error",this)},s}); -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -o errexit #abort if any command fails 3 | me=$(basename "$0") 4 | 5 | help_message="\ 6 | Usage: $me [-c FILE] [] 7 | Deploy generated files to a git branch. 8 | 9 | Options: 10 | 11 | -h, --help Show this help information. 12 | -v, --verbose Increase verbosity. Useful for debugging. 13 | -e, --allow-empty Allow deployment of an empty directory. 14 | -m, --message MESSAGE Specify the message used when committing on the 15 | deploy branch. 16 | -n, --no-hash Don't append the source commit's hash to the deploy 17 | commit's message. 18 | -c, --config-file PATH Override default & environment variables' values 19 | with those in set in the file at 'PATH'. Must be the 20 | first option specified. 21 | 22 | Variables: 23 | 24 | GIT_DEPLOY_DIR Folder path containing the files to deploy. 25 | GIT_DEPLOY_BRANCH Commit deployable files to this branch. 26 | GIT_DEPLOY_REPO Push the deploy branch to this repository. 27 | 28 | These variables have default values defined in the script. The defaults can be 29 | overridden by environment variables. Any environment variables are overridden 30 | by values set in a '.env' file (if it exists), and in turn by those set in a 31 | file specified by the '--config-file' option." 32 | 33 | bundle exec middleman build --clean 34 | 35 | parse_args() { 36 | # Set args from a local environment file. 37 | if [ -e ".env" ]; then 38 | source .env 39 | fi 40 | 41 | # Set args from file specified on the command-line. 42 | if [[ $1 = "-c" || $1 = "--config-file" ]]; then 43 | source "$2" 44 | shift 2 45 | fi 46 | 47 | # Parse arg flags 48 | # If something is exposed as an environment variable, set/overwrite it 49 | # here. Otherwise, set/overwrite the internal variable instead. 50 | while : ; do 51 | if [[ $1 = "-h" || $1 = "--help" ]]; then 52 | echo "$help_message" 53 | return 0 54 | elif [[ $1 = "-v" || $1 = "--verbose" ]]; then 55 | verbose=true 56 | shift 57 | elif [[ $1 = "-e" || $1 = "--allow-empty" ]]; then 58 | allow_empty=true 59 | shift 60 | elif [[ ( $1 = "-m" || $1 = "--message" ) && -n $2 ]]; then 61 | commit_message=$2 62 | shift 2 63 | elif [[ $1 = "-n" || $1 = "--no-hash" ]]; then 64 | GIT_DEPLOY_APPEND_HASH=false 65 | shift 66 | else 67 | break 68 | fi 69 | done 70 | 71 | # Set internal option vars from the environment and arg flags. All internal 72 | # vars should be declared here, with sane defaults if applicable. 73 | 74 | # Source directory & target branch. 75 | deploy_directory=build 76 | deploy_branch=gh-pages 77 | 78 | #if no user identity is already set in the current git environment, use this: 79 | default_username=${GIT_DEPLOY_USERNAME:-deploy.sh} 80 | default_email=${GIT_DEPLOY_EMAIL:-} 81 | 82 | #repository to deploy to. must be readable and writable. 83 | repo=origin 84 | 85 | #append commit hash to the end of message by default 86 | append_hash=${GIT_DEPLOY_APPEND_HASH:-true} 87 | } 88 | 89 | main() { 90 | parse_args "$@" 91 | 92 | enable_expanded_output 93 | 94 | if ! git diff --exit-code --quiet --cached; then 95 | echo Aborting due to uncommitted changes in the index >&2 96 | return 1 97 | fi 98 | 99 | commit_title=`git log -n 1 --format="%s" HEAD` 100 | commit_hash=` git log -n 1 --format="%H" HEAD` 101 | 102 | #default commit message uses last title if a custom one is not supplied 103 | if [[ -z $commit_message ]]; then 104 | commit_message="publish: $commit_title" 105 | fi 106 | 107 | #append hash to commit message unless no hash flag was found 108 | if [ $append_hash = true ]; then 109 | commit_message="$commit_message"$'\n\n'"generated from commit $commit_hash" 110 | fi 111 | 112 | previous_branch=`git rev-parse --abbrev-ref HEAD` 113 | 114 | if [ ! -d "$deploy_directory" ]; then 115 | echo "Deploy directory '$deploy_directory' does not exist. Aborting." >&2 116 | return 1 117 | fi 118 | 119 | # must use short form of flag in ls for compatibility with OS X and BSD 120 | if [[ -z `ls -A "$deploy_directory" 2> /dev/null` && -z $allow_empty ]]; then 121 | echo "Deploy directory '$deploy_directory' is empty. Aborting. If you're sure you want to deploy an empty tree, use the --allow-empty / -e flag." >&2 122 | return 1 123 | fi 124 | 125 | if git ls-remote --exit-code $repo "refs/heads/$deploy_branch" ; then 126 | # deploy_branch exists in $repo; make sure we have the latest version 127 | 128 | disable_expanded_output 129 | git fetch --force $repo $deploy_branch:$deploy_branch 130 | enable_expanded_output 131 | fi 132 | 133 | # check if deploy_branch exists locally 134 | if git show-ref --verify --quiet "refs/heads/$deploy_branch" 135 | then incremental_deploy 136 | else initial_deploy 137 | fi 138 | 139 | restore_head 140 | } 141 | 142 | initial_deploy() { 143 | git --work-tree "$deploy_directory" checkout --orphan $deploy_branch 144 | git --work-tree "$deploy_directory" add --all 145 | commit+push 146 | } 147 | 148 | incremental_deploy() { 149 | #make deploy_branch the current branch 150 | git symbolic-ref HEAD refs/heads/$deploy_branch 151 | #put the previously committed contents of deploy_branch into the index 152 | git --work-tree "$deploy_directory" reset --mixed --quiet 153 | git --work-tree "$deploy_directory" add --all 154 | 155 | set +o errexit 156 | diff=$(git --work-tree "$deploy_directory" diff --exit-code --quiet HEAD --)$? 157 | set -o errexit 158 | case $diff in 159 | 0) echo No changes to files in $deploy_directory. Skipping commit.;; 160 | 1) commit+push;; 161 | *) 162 | echo git diff exited with code $diff. Aborting. Staying on branch $deploy_branch so you can debug. To switch back to master, use: git symbolic-ref HEAD refs/heads/master && git reset --mixed >&2 163 | return $diff 164 | ;; 165 | esac 166 | } 167 | 168 | commit+push() { 169 | set_user_id 170 | git --work-tree "$deploy_directory" commit -m "$commit_message" 171 | 172 | disable_expanded_output 173 | #--quiet is important here to avoid outputting the repo URL, which may contain a secret token 174 | git push --quiet $repo $deploy_branch 175 | enable_expanded_output 176 | } 177 | 178 | #echo expanded commands as they are executed (for debugging) 179 | enable_expanded_output() { 180 | if [ $verbose ]; then 181 | set -o xtrace 182 | set +o verbose 183 | fi 184 | } 185 | 186 | #this is used to avoid outputting the repo URL, which may contain a secret token 187 | disable_expanded_output() { 188 | if [ $verbose ]; then 189 | set +o xtrace 190 | set -o verbose 191 | fi 192 | } 193 | 194 | set_user_id() { 195 | if [[ -z `git config user.name` ]]; then 196 | git config user.name "$default_username" 197 | fi 198 | if [[ -z `git config user.email` ]]; then 199 | git config user.email "$default_email" 200 | fi 201 | } 202 | 203 | restore_head() { 204 | if [[ $previous_branch = "HEAD" ]]; then 205 | #we weren't on any branch before, so just set HEAD back to the commit it was on 206 | git update-ref --no-deref HEAD $commit_hash $deploy_branch 207 | else 208 | git symbolic-ref HEAD refs/heads/$previous_branch 209 | fi 210 | 211 | git reset --mixed 212 | } 213 | 214 | filter() { 215 | sed -e "s|$repo|\$repo|g" 216 | } 217 | 218 | sanitize() { 219 | "$@" 2> >(filter 1>&2) | filter 220 | } 221 | 222 | [[ $1 = --source-only ]] || main "$@" -------------------------------------------------------------------------------- /source/stylesheets/_normalize.scss: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /source/stylesheets/screen.css.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @import 'normalize'; 3 | @import 'variables'; 4 | @import 'icon-font'; 5 | 6 | /* 7 | Copyright 2008-2013 Concur Technologies, Inc. 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); you may 10 | not use this file except in compliance with the License. You may obtain 11 | a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 17 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 18 | License for the specific language governing permissions and limitations 19 | under the License. 20 | */ 21 | 22 | //////////////////////////////////////////////////////////////////////////////// 23 | // GENERAL STUFF 24 | //////////////////////////////////////////////////////////////////////////////// 25 | 26 | html, body { 27 | color: $main-text; 28 | padding: 0; 29 | margin: 0; 30 | -webkit-font-smoothing: antialiased; 31 | -moz-osx-font-smoothing: grayscale; 32 | @extend %default-font; 33 | background-color: $main-bg; 34 | height: 100%; 35 | -webkit-text-size-adjust: none; /* Never autoresize text */ 36 | } 37 | 38 | //////////////////////////////////////////////////////////////////////////////// 39 | // TABLE OF CONTENTS 40 | //////////////////////////////////////////////////////////////////////////////// 41 | 42 | #toc > ul > li > a > span { 43 | float: right; 44 | background-color: #2484FF; 45 | border-radius: 40px; 46 | width: 20px; 47 | } 48 | 49 | @mixin embossed-bg { 50 | background: 51 | linear-gradient(to bottom, rgba(#000, 0.2), rgba(#000, 0) 8px), 52 | linear-gradient(to top, rgba(#000, 0.2), rgba(#000, 0) 8px), 53 | linear-gradient(to bottom, rgba($nav-embossed-border-top, 1), rgba($nav-embossed-border-top, 0) 1.5px), 54 | linear-gradient(to top, rgba($nav-embossed-border-bottom, 1), rgba($nav-embossed-border-bottom, 0) 1.5px), 55 | $nav-subitem-bg; 56 | } 57 | 58 | .tocify-wrapper { 59 | transition: left 0.3s ease-in-out; 60 | 61 | overflow-y: auto; 62 | overflow-x: hidden; 63 | position: fixed; 64 | z-index: 30; 65 | top: 0; 66 | left: 0; 67 | bottom: 0; 68 | width: $nav-width; 69 | background-color: $nav-bg; 70 | font-size: 13px; 71 | font-weight: bold; 72 | 73 | // language selector for mobile devices 74 | .lang-selector { 75 | display: none; 76 | a { 77 | padding-top: 0.5em; 78 | padding-bottom: 0.5em; 79 | } 80 | } 81 | 82 | // This is the logo at the top of the ToC 83 | &>img { 84 | display: block; 85 | max-width: 100%; 86 | } 87 | 88 | &>.search { 89 | position: relative; 90 | 91 | input { 92 | background: $nav-bg; 93 | border-width: 0 0 1px 0; 94 | border-color: $search-box-border-color; 95 | padding: 6px 0 6px 20px; 96 | box-sizing: border-box; 97 | margin: $nav-v-padding $nav-padding; 98 | width: $nav-width - 30; 99 | outline: none; 100 | color: $nav-text; 101 | border-radius: 0; /* ios has a default border radius */ 102 | } 103 | 104 | &:before { 105 | position: absolute; 106 | top: 17px; 107 | left: $nav-padding; 108 | color: $nav-text; 109 | @extend %icon-search; 110 | } 111 | } 112 | 113 | img+.tocify { 114 | margin-top: $logo-margin; 115 | } 116 | 117 | .search-results { 118 | margin-top: 0; 119 | box-sizing: border-box; 120 | height: 0; 121 | overflow-y: auto; 122 | overflow-x: hidden; 123 | transition-property: height, margin; 124 | transition-duration: 180ms; 125 | transition-timing-function: ease-in-out; 126 | &.visible { 127 | height: 30%; 128 | margin-bottom: 1em; 129 | } 130 | 131 | @include embossed-bg; 132 | 133 | li { 134 | margin: 1em $nav-padding; 135 | line-height: 1; 136 | } 137 | 138 | a { 139 | color: $nav-text; 140 | text-decoration: none; 141 | 142 | &:hover { 143 | text-decoration: underline; 144 | } 145 | } 146 | } 147 | 148 | 149 | .tocify-item>a, .toc-footer li { 150 | padding: 0 $nav-padding 0 $nav-padding; 151 | display: block; 152 | overflow-x: hidden; 153 | white-space: nowrap; 154 | text-overflow: ellipsis; 155 | } 156 | 157 | // The Table of Contents is composed of multiple nested 158 | // unordered lists. These styles remove the default 159 | // styling of an unordered list because it is ugly. 160 | ul, li { 161 | list-style: none; 162 | margin: 0; 163 | padding: 0; 164 | line-height: 28px; 165 | } 166 | 167 | li { 168 | color: $nav-text; 169 | transition-property: background; 170 | transition-timing-function: linear; 171 | transition-duration: 230ms; 172 | } 173 | 174 | // This is the currently selected ToC entry 175 | .tocify-focus { 176 | box-shadow: 0px 1px 0px $nav-active-shadow; 177 | background-color: $nav-active-bg; 178 | color: $nav-active-text; 179 | } 180 | 181 | // Subheaders are the submenus that slide open 182 | // in the table of contents. 183 | .tocify-subheader { 184 | display: none; // tocify will override this when needed 185 | background-color: $nav-subitem-bg; 186 | font-weight: 500; 187 | .tocify-item>a { 188 | padding-left: $nav-padding + $nav-indent; 189 | font-size: 12px; 190 | } 191 | 192 | // for embossed look: 193 | @include embossed-bg; 194 | &>li:last-child { 195 | box-shadow: none; // otherwise it'll overflow out of the subheader 196 | } 197 | } 198 | 199 | .toc-footer { 200 | padding: 1em 0; 201 | margin-top: 1em; 202 | border-top: 1px dashed $nav-footer-border-color; 203 | 204 | li,a { 205 | color: $nav-text; 206 | text-decoration: none; 207 | } 208 | 209 | a:hover { 210 | text-decoration: underline; 211 | } 212 | 213 | li { 214 | font-size: 0.8em; 215 | line-height: 1.7; 216 | text-decoration: none; 217 | } 218 | } 219 | 220 | } 221 | 222 | // button to show navigation on mobile devices 223 | #nav-button { 224 | span { 225 | display: block; 226 | $side-pad: $main-padding / 2 - 8px; 227 | padding: $side-pad $side-pad $side-pad; 228 | background-color: rgba($main-bg, 0.7); 229 | transform-origin: 0 0; 230 | transform: rotate(-90deg) translate(-100%, 0); 231 | border-radius: 0 0 0 5px; 232 | } 233 | padding: 0 1.5em 5em 0; // increase touch size area 234 | display: none; 235 | position: fixed; 236 | top: 0; 237 | left: 0; 238 | z-index: 100; 239 | color: #000; 240 | text-decoration: none; 241 | font-weight: bold; 242 | opacity: 0.7; 243 | line-height: 16px; 244 | img { 245 | height: 16px; 246 | vertical-align: bottom; 247 | } 248 | 249 | transition: left 0.3s ease-in-out; 250 | 251 | &:hover { opacity: 1; } 252 | &.open {left: $nav-width} 253 | } 254 | 255 | 256 | //////////////////////////////////////////////////////////////////////////////// 257 | // PAGE LAYOUT AND CODE SAMPLE BACKGROUND 258 | //////////////////////////////////////////////////////////////////////////////// 259 | 260 | .page-wrapper { 261 | margin-left: $nav-width; 262 | position: relative; 263 | z-index: 10; 264 | background-color: $main-bg; 265 | min-height: 100%; 266 | 267 | padding-bottom: 1px; // prevent margin overflow 268 | 269 | // The dark box is what gives the code samples their dark background. 270 | // It sits essentially under the actual content block, which has a 271 | // transparent background. 272 | // I know, it's hackish, but it's the simplist way to make the left 273 | // half of the content always this background color. 274 | .dark-box { 275 | width: $examples-width; 276 | background-color: $examples-bg; 277 | position: absolute; 278 | right: 0; 279 | top: 0; 280 | bottom: 0; 281 | } 282 | 283 | .lang-selector { 284 | position: fixed; 285 | z-index: 50; 286 | border-bottom: 5px solid $lang-select-active-bg; 287 | } 288 | } 289 | 290 | .lang-selector { 291 | background-color: $lang-select-bg; 292 | width: 100%; 293 | font-weight: bold; 294 | a { 295 | display: block; 296 | float:left; 297 | color: $lang-select-text; 298 | text-decoration: none; 299 | padding: 0 10px; 300 | line-height: 30px; 301 | outline: 0; 302 | 303 | &:active, &:focus { 304 | background-color: $lang-select-pressed-bg; 305 | color: $lang-select-pressed-text; 306 | } 307 | 308 | &.active { 309 | background-color: $lang-select-active-bg; 310 | color: $lang-select-active-text; 311 | } 312 | } 313 | 314 | &:after { 315 | content: ''; 316 | clear: both; 317 | display: block; 318 | } 319 | } 320 | 321 | //////////////////////////////////////////////////////////////////////////////// 322 | // CONTENT STYLES 323 | //////////////////////////////////////////////////////////////////////////////// 324 | // This is all the stuff with the light background in the left half of the page 325 | 326 | .content { 327 | // to place content above the dark box 328 | position: relative; 329 | z-index: 30; 330 | 331 | &:after { 332 | content: ''; 333 | display: block; 334 | clear: both; 335 | } 336 | 337 | &>h1, &>h2, &>h3, &>h4, &>h5, &>h6, &>p, &>table, &>ul, &>ol, &>aside, &>dl { 338 | margin-right: $examples-width; 339 | padding: 0 $main-padding; 340 | box-sizing: border-box; 341 | display: block; 342 | text-shadow: $main-embossed-text-shadow; 343 | 344 | @extend %left-col; 345 | } 346 | 347 | &>ul, &>ol { 348 | padding-left: $main-padding + 15px; 349 | } 350 | 351 | // the div is the tocify hidden div for placeholding stuff 352 | &>h1, &>h2, &>div { 353 | clear:both; 354 | } 355 | 356 | h1 { 357 | @extend %header-font; 358 | font-size: 30px; 359 | padding-top: 0.5em; 360 | padding-bottom: 0.5em; 361 | border-bottom: 1px solid #ccc; 362 | margin-bottom: $h1-margin-bottom; 363 | margin-top: 2em; 364 | border-top: 1px solid #ddd; 365 | background-image: linear-gradient(to bottom, #fff, #f9f9f9); 366 | } 367 | 368 | h1:first-child, div:first-child + h1 { 369 | border-top-width: 0; 370 | margin-top: 0; 371 | } 372 | 373 | h2 { 374 | @extend %header-font; 375 | font-size: 20px; 376 | margin-top: 4em; 377 | margin-bottom: 0; 378 | border-top: 1px solid #ccc; 379 | padding-top: 1.2em; 380 | padding-bottom: 1.2em; 381 | background-image: linear-gradient(to bottom, rgba(#fff, 0.4), rgba(#fff, 0)); 382 | } 383 | 384 | // h2s right after h1s should bump right up 385 | // against the h1s. 386 | h1 + h2, h1 + div + h2 { 387 | margin-top: $h1-margin-bottom * -1; 388 | border-top: none; 389 | } 390 | 391 | h3, h4, h5, h6 { 392 | @extend %header-font; 393 | font-size: 15px; 394 | margin-top: 2.5em; 395 | margin-bottom: 0.8em; 396 | } 397 | 398 | h4, h5, h6 { 399 | font-size: 10px; 400 | } 401 | 402 | hr { 403 | margin: 2em 0; 404 | border-top: 2px solid $examples-bg; 405 | border-bottom: 2px solid $main-bg; 406 | } 407 | 408 | table { 409 | margin-bottom: 1em; 410 | overflow: auto; 411 | th,td { 412 | text-align: left; 413 | vertical-align: top; 414 | line-height: 1.6; 415 | } 416 | 417 | th { 418 | padding: 5px 10px; 419 | border-bottom: 1px solid #ccc; 420 | vertical-align: bottom; 421 | } 422 | 423 | td { 424 | padding: 10px; 425 | } 426 | 427 | tr:last-child { 428 | border-bottom: 1px solid #ccc; 429 | } 430 | 431 | tr:nth-child(odd)>td { 432 | background-color: lighten($main-bg,4.2%); 433 | } 434 | 435 | tr:nth-child(even)>td { 436 | background-color: lighten($main-bg,2.4%); 437 | } 438 | } 439 | 440 | dt { 441 | font-weight: bold; 442 | } 443 | 444 | dd { 445 | margin-left: 15px; 446 | } 447 | 448 | p, li, dt, dd { 449 | line-height: 1.6; 450 | margin-top: 0; 451 | } 452 | 453 | img { 454 | max-width: 100%; 455 | } 456 | 457 | code { 458 | background-color: rgba(0,0,0,0.05); 459 | padding: 3px; 460 | border-radius: 3px; 461 | @extend %break-words; 462 | @extend %code-font; 463 | } 464 | 465 | pre>code { 466 | background-color: transparent; 467 | padding: 0; 468 | } 469 | 470 | aside { 471 | padding-top: 1em; 472 | padding-bottom: 1em; 473 | text-shadow: 0 1px 0 lighten($aside-notice-bg, 15%); 474 | margin-top: 1.5em; 475 | margin-bottom: 1.5em; 476 | background: $aside-notice-bg; 477 | line-height: 1.6; 478 | 479 | &.warning { 480 | background-color: $aside-warning-bg; 481 | text-shadow: 0 1px 0 lighten($aside-warning-bg, 15%); 482 | } 483 | 484 | &.success { 485 | background-color: $aside-success-bg; 486 | text-shadow: 0 1px 0 lighten($aside-success-bg, 15%); 487 | } 488 | } 489 | 490 | aside:before { 491 | vertical-align: middle; 492 | padding-right: 0.5em; 493 | font-size: 14px; 494 | } 495 | 496 | aside.notice:before { 497 | @extend %icon-info-sign; 498 | } 499 | 500 | aside.warning:before { 501 | @extend %icon-exclamation-sign; 502 | } 503 | 504 | aside.success:before { 505 | @extend %icon-ok-sign; 506 | } 507 | 508 | .search-highlight { 509 | padding: 2px; 510 | margin: -2px; 511 | border-radius: 4px; 512 | border: 1px solid #F7E633; 513 | text-shadow: 1px 1px 0 #666; 514 | background: linear-gradient(to top left, #F7E633 0%, #F1D32F 100%); 515 | } 516 | } 517 | 518 | //////////////////////////////////////////////////////////////////////////////// 519 | // CODE SAMPLE STYLES 520 | //////////////////////////////////////////////////////////////////////////////// 521 | // This is all the stuff that appears in the right half of the page 522 | 523 | .content { 524 | pre, blockquote { 525 | background-color: $code-bg; 526 | color: #fff; 527 | 528 | padding: 2em $main-padding; 529 | margin: 0; 530 | width: $examples-width; 531 | 532 | float:right; 533 | clear:right; 534 | 535 | box-sizing: border-box; 536 | text-shadow: 0px 1px 2px rgba(0,0,0,0.4); 537 | 538 | @extend %right-col; 539 | 540 | &>p { margin: 0; } 541 | 542 | a { 543 | color: #fff; 544 | text-decoration: none; 545 | border-bottom: dashed 1px #ccc; 546 | } 547 | } 548 | 549 | pre { 550 | @extend %code-font; 551 | } 552 | 553 | blockquote { 554 | &>p { 555 | background-color: $code-annotation-bg; 556 | border-radius: 5px; 557 | padding: $code-annotation-padding; 558 | color: #ccc; 559 | border-top: 1px solid #000; 560 | border-bottom: 1px solid #404040; 561 | } 562 | } 563 | } 564 | 565 | //////////////////////////////////////////////////////////////////////////////// 566 | // RESPONSIVE DESIGN 567 | //////////////////////////////////////////////////////////////////////////////// 568 | // These are the styles for phones and tablets 569 | // There are also a couple styles disperesed 570 | 571 | @media (max-width: $tablet-width) { 572 | .tocify-wrapper { 573 | left: -$nav-width; 574 | 575 | &.open { 576 | left: 0; 577 | } 578 | } 579 | 580 | .page-wrapper { 581 | margin-left: 0; 582 | } 583 | 584 | #nav-button { 585 | display: block; 586 | } 587 | 588 | .tocify-wrapper .tocify-item > a { 589 | padding-top: 0.3em; 590 | padding-bottom: 0.3em; 591 | } 592 | } 593 | 594 | @media (max-width: $phone-width) { 595 | .dark-box { 596 | display: none; 597 | } 598 | 599 | %left-col { 600 | margin-right: 0; 601 | } 602 | 603 | .tocify-wrapper .lang-selector { 604 | display: block; 605 | } 606 | 607 | .page-wrapper .lang-selector { 608 | display: none; 609 | } 610 | 611 | %right-col { 612 | width: auto; 613 | float: none; 614 | } 615 | 616 | %right-col + %left-col { 617 | margin-top: $main-padding; 618 | } 619 | } 620 | 621 | .highlight .c, .highlight .cm, .highlight .c1, .highlight .cs { 622 | color: #909090; 623 | } 624 | 625 | .highlight, .highlight .w { 626 | background-color: $code-bg; 627 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /source/javascripts/lib/_jquery.tocify.js: -------------------------------------------------------------------------------- 1 | /* jquery Tocify - v1.8.0 - 2013-09-16 2 | * http://www.gregfranko.com/jquery.tocify.js/ 3 | * Copyright (c) 2013 Greg Franko; Licensed MIT 4 | * Modified lightly by Robert Lord to fix a bug I found, 5 | * and also so it adds ids to headers 6 | * also because I want height caching, since the 7 | * height lookup for h1s and h2s was causing serious 8 | * lag spikes below 30 fps */ 9 | 10 | // 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. 11 | (function(tocify) { 12 | 13 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 14 | "use strict"; 15 | 16 | // Calls the second IIFE and locally passes in the global jQuery, window, and document objects 17 | tocify(window.jQuery, window, document); 18 | 19 | } 20 | 21 | // 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. 22 | (function($, window, document, undefined) { 23 | 24 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 25 | "use strict"; 26 | 27 | var tocClassName = "tocify", 28 | tocClass = "." + tocClassName, 29 | tocFocusClassName = "tocify-focus", 30 | tocHoverClassName = "tocify-hover", 31 | hideTocClassName = "tocify-hide", 32 | hideTocClass = "." + hideTocClassName, 33 | headerClassName = "tocify-header", 34 | headerClass = "." + headerClassName, 35 | subheaderClassName = "tocify-subheader", 36 | subheaderClass = "." + subheaderClassName, 37 | itemClassName = "tocify-item", 38 | itemClass = "." + itemClassName, 39 | extendPageClassName = "tocify-extend-page", 40 | extendPageClass = "." + extendPageClassName; 41 | 42 | // Calling the jQueryUI Widget Factory Method 43 | $.widget("toc.tocify", { 44 | 45 | //Plugin version 46 | version: "1.8.0", 47 | 48 | // These options will be used as defaults 49 | options: { 50 | 51 | // **context**: Accepts String: Any jQuery selector 52 | // The container element that holds all of the elements used to generate the table of contents 53 | context: "body", 54 | 55 | // **ignoreSelector**: Accepts String: Any jQuery selector 56 | // A selector to any element that would be matched by selectors that you wish to be ignored 57 | ignoreSelector: null, 58 | 59 | // **selectors**: Accepts an Array of Strings: Any jQuery selectors 60 | // 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 61 | selectors: "h1, h2, h3", 62 | 63 | // **showAndHide**: Accepts a boolean: true or false 64 | // Used to determine if elements should be shown and hidden 65 | showAndHide: true, 66 | 67 | // **showEffect**: Accepts String: "none", "fadeIn", "show", or "slideDown" 68 | // Used to display any of the table of contents nested items 69 | showEffect: "slideDown", 70 | 71 | // **showEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast" 72 | // The time duration of the show animation 73 | showEffectSpeed: "medium", 74 | 75 | // **hideEffect**: Accepts String: "none", "fadeOut", "hide", or "slideUp" 76 | // Used to hide any of the table of contents nested items 77 | hideEffect: "slideUp", 78 | 79 | // **hideEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast" 80 | // The time duration of the hide animation 81 | hideEffectSpeed: "medium", 82 | 83 | // **smoothScroll**: Accepts a boolean: true or false 84 | // Determines if a jQuery animation should be used to scroll to specific table of contents items on the page 85 | smoothScroll: true, 86 | 87 | // **smoothScrollSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast" 88 | // The time duration of the smoothScroll animation 89 | smoothScrollSpeed: "medium", 90 | 91 | // **scrollTo**: Accepts Number (pixels) 92 | // The amount of space between the top of page and the selected table of contents item after the page has been scrolled 93 | scrollTo: 0, 94 | 95 | // **showAndHideOnScroll**: Accepts a boolean: true or false 96 | // Determines if table of contents nested items should be shown and hidden while scrolling 97 | showAndHideOnScroll: true, 98 | 99 | // **highlightOnScroll**: Accepts a boolean: true or false 100 | // Determines if table of contents nested items should be highlighted (set to a different color) while scrolling 101 | highlightOnScroll: true, 102 | 103 | // **highlightOffset**: Accepts a number 104 | // The offset distance in pixels to trigger the next active table of contents item 105 | highlightOffset: 40, 106 | 107 | // **theme**: Accepts a string: "bootstrap", "jqueryui", or "none" 108 | // Determines if Twitter Bootstrap, jQueryUI, or Tocify classes should be added to the table of contents 109 | theme: "bootstrap", 110 | 111 | // **extendPage**: Accepts a boolean: true or false 112 | // 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 113 | extendPage: true, 114 | 115 | // **extendPageOffset**: Accepts a number: pixels 116 | // How close to the bottom of the page a user must scroll before the page is extended 117 | extendPageOffset: 100, 118 | 119 | // **history**: Accepts a boolean: true or false 120 | // Adds a hash to the page url to maintain history 121 | history: true, 122 | 123 | // **scrollHistory**: Accepts a boolean: true or false 124 | // Adds a hash to the page url, to maintain history, when scrolling to a TOC item 125 | scrollHistory: false, 126 | 127 | // **hashGenerator**: How the hash value (the anchor segment of the URL, following the 128 | // # character) will be generated. 129 | // 130 | // "compact" (default) - #CompressesEverythingTogether 131 | // "pretty" - #looks-like-a-nice-url-and-is-easily-readable 132 | // function(text, element){} - Your own hash generation function that accepts the text as an 133 | // argument, and returns the hash value. 134 | hashGenerator: "compact", 135 | 136 | // **highlightDefault**: Accepts a boolean: true or false 137 | // Set's the first TOC item as active if no other TOC item is active. 138 | highlightDefault: true 139 | 140 | }, 141 | 142 | // _Create 143 | // ------- 144 | // Constructs the plugin. Only called once. 145 | _create: function() { 146 | 147 | var self = this; 148 | 149 | self.tocifyWrapper = $('.tocify-wrapper'); 150 | self.extendPageScroll = true; 151 | 152 | // Internal array that keeps track of all TOC items (Helps to recognize if there are duplicate TOC item strings) 153 | self.items = []; 154 | 155 | // Generates the HTML for the dynamic table of contents 156 | self._generateToc(); 157 | 158 | // Caches heights and anchors 159 | self.cachedHeights = [], 160 | self.cachedAnchors = []; 161 | 162 | // Adds CSS classes to the newly generated table of contents HTML 163 | self._addCSSClasses(); 164 | 165 | self.webkit = (function() { 166 | 167 | for(var prop in window) { 168 | 169 | if(prop) { 170 | 171 | if(prop.toLowerCase().indexOf("webkit") !== -1) { 172 | 173 | return true; 174 | 175 | } 176 | 177 | } 178 | 179 | } 180 | 181 | return false; 182 | 183 | }()); 184 | 185 | // Adds jQuery event handlers to the newly generated table of contents 186 | self._setEventHandlers(); 187 | 188 | // Binding to the Window load event to make sure the correct scrollTop is calculated 189 | $(window).load(function() { 190 | 191 | // Sets the active TOC item 192 | self._setActiveElement(true); 193 | 194 | // Once all animations on the page are complete, this callback function will be called 195 | $("html, body").promise().done(function() { 196 | 197 | setTimeout(function() { 198 | 199 | self.extendPageScroll = false; 200 | 201 | },0); 202 | 203 | }); 204 | 205 | }); 206 | 207 | }, 208 | 209 | // _generateToc 210 | // ------------ 211 | // Generates the HTML for the dynamic table of contents 212 | _generateToc: function() { 213 | 214 | // _Local variables_ 215 | 216 | // Stores the plugin context in the self variable 217 | var self = this, 218 | 219 | // All of the HTML tags found within the context provided (i.e. body) that match the top level jQuery selector above 220 | firstElem, 221 | 222 | // Instantiated variable that will store the top level newly created unordered list DOM element 223 | ul, 224 | ignoreSelector = self.options.ignoreSelector; 225 | 226 | // If the selectors option has a comma within the string 227 | if(this.options.selectors.indexOf(",") !== -1) { 228 | 229 | // Grabs the first selector from the string 230 | firstElem = $(this.options.context).find(this.options.selectors.replace(/ /g,"").substr(0, this.options.selectors.indexOf(","))); 231 | 232 | } 233 | 234 | // If the selectors option does not have a comman within the string 235 | else { 236 | 237 | // Grabs the first selector from the string and makes sure there are no spaces 238 | firstElem = $(this.options.context).find(this.options.selectors.replace(/ /g,"")); 239 | 240 | } 241 | 242 | if(!firstElem.length) { 243 | 244 | self.element.addClass(hideTocClassName); 245 | 246 | return; 247 | 248 | } 249 | 250 | self.element.addClass(tocClassName); 251 | 252 | // Loops through each top level selector 253 | firstElem.each(function(index) { 254 | 255 | //If the element matches the ignoreSelector then we skip it 256 | if($(this).is(ignoreSelector)) { 257 | return; 258 | } 259 | 260 | // Creates an unordered list HTML element and adds a dynamic ID and standard class name 261 | ul = $("