├── .gitignore ├── .travis.yml ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── config.rb ├── meta.json └── source ├── fonts ├── icomoon.eot ├── icomoon.svg ├── icomoon.ttf └── icomoon.woff ├── images ├── apod.jpg ├── earth.png ├── logo.png ├── mars.jpg └── navbar.png ├── includes └── _errors.md ├── index.md ├── javascripts ├── all.js ├── all_nosearch.js ├── app │ ├── lang.js │ ├── search.js │ └── toc.js └── lib │ ├── energize.js │ ├── jquery.highlight.js │ ├── jquery.tocify.js │ ├── jquery_ui.js │ └── lunr.js ├── layouts └── layout.erb └── stylesheets ├── icon-font.scss ├── normalize.css ├── print.css.scss ├── screen.css.scss ├── syntax.css.scss.erb └── variables.scss /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | coverage 6 | InstalledFiles 7 | lib/bundler/man 8 | pkg 9 | rdoc 10 | spec/reports 11 | test/tmp 12 | test/version_tmp 13 | tmp 14 | *.DS_STORE 15 | build/ 16 | .cache 17 | 18 | # YARD artifacts 19 | .yardoc 20 | _yardoc 21 | doc/ 22 | .idea/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | rvm: 2 | - 1.9.3 3 | - 2.0.0 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:trusty 2 | 3 | RUN apt-get update 4 | RUN apt-get install -yq ruby ruby-dev build-essential 5 | RUN gem install --no-ri --no-rdoc bundler 6 | ADD Gemfile /app/Gemfile 7 | ADD Gemfile.lock /app/Gemfile.lock 8 | RUN cd /app; bundle install 9 | ADD . /app 10 | EXPOSE 4567 11 | WORKDIR /app 12 | CMD ["bundle", "exec", "middleman", "server"] -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # If you have OpenSSL installed, we recommend updating 2 | # the following line to use "https" 3 | source 'http://rubygems.org' 4 | 5 | gem "rouge", "1.7.2" 6 | 7 | gem "middleman", "~>3.3.0" 8 | 9 | # For syntax highlighting 10 | gem "middleman-syntax" 11 | 12 | # Plugin for middleman to generate Github pages 13 | gem 'middleman-gh-pages' 14 | 15 | # Live-reloading plugin 16 | gem "middleman-livereload", "~> 3.3.0" 17 | 18 | gem 'redcarpet', '~> 3.2.1' 19 | 20 | # For faster file watcher updates on Windows: 21 | gem "wdm", "~> 0.1.0", :platforms => [:mswin, :mingw] 22 | 23 | # Cross-templating language block fix for Ruby 1.8 24 | platforms :mri_18 do 25 | gem "ruby18_source_location" 26 | end 27 | 28 | gem "rake", "~> 10.4.0" 29 | 30 | gem 'therubyracer', :platforms => :ruby -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | activesupport (4.1.9) 5 | i18n (~> 0.6, >= 0.6.9) 6 | json (~> 1.7, >= 1.7.7) 7 | minitest (~> 5.1) 8 | thread_safe (~> 0.1) 9 | tzinfo (~> 1.1) 10 | celluloid (0.16.0) 11 | timers (~> 4.0.0) 12 | chunky_png (1.3.3) 13 | coffee-script (2.3.0) 14 | coffee-script-source 15 | execjs 16 | coffee-script-source (1.8.0) 17 | compass (1.0.1) 18 | chunky_png (~> 1.2) 19 | compass-core (~> 1.0.1) 20 | compass-import-once (~> 1.0.5) 21 | rb-fsevent (>= 0.9.3) 22 | rb-inotify (>= 0.9) 23 | sass (>= 3.3.13, < 3.5) 24 | compass-core (1.0.1) 25 | multi_json (~> 1.0) 26 | sass (>= 3.3.0, < 3.5) 27 | compass-import-once (1.0.5) 28 | sass (>= 3.2, < 3.5) 29 | em-websocket (0.5.1) 30 | eventmachine (>= 0.12.9) 31 | http_parser.rb (~> 0.6.0) 32 | erubis (2.7.0) 33 | eventmachine (1.0.4) 34 | execjs (2.2.2) 35 | ffi (1.9.6) 36 | haml (4.0.6) 37 | tilt 38 | hike (1.2.3) 39 | hitimes (1.2.2) 40 | hooks (0.4.0) 41 | uber (~> 0.0.4) 42 | http_parser.rb (0.6.0) 43 | i18n (0.6.11) 44 | json (1.8.2) 45 | kramdown (1.5.0) 46 | libv8 (3.16.14.7) 47 | listen (2.8.5) 48 | celluloid (>= 0.15.2) 49 | rb-fsevent (>= 0.9.3) 50 | rb-inotify (>= 0.9) 51 | middleman (3.3.7) 52 | coffee-script (~> 2.2) 53 | compass (>= 1.0.0, < 2.0.0) 54 | compass-import-once (= 1.0.5) 55 | execjs (~> 2.0) 56 | haml (>= 4.0.5) 57 | kramdown (~> 1.2) 58 | middleman-core (= 3.3.7) 59 | middleman-sprockets (>= 3.1.2) 60 | sass (>= 3.4.0, < 4.0) 61 | uglifier (~> 2.5) 62 | middleman-core (3.3.7) 63 | activesupport (~> 4.1.0) 64 | bundler (~> 1.1) 65 | erubis 66 | hooks (~> 0.3) 67 | i18n (~> 0.6.9) 68 | listen (>= 2.7.9, < 3.0) 69 | padrino-helpers (~> 0.12.3) 70 | rack (>= 1.4.5, < 2.0) 71 | rack-test (~> 0.6.2) 72 | thor (>= 0.15.2, < 2.0) 73 | tilt (~> 1.4.1, < 2.0) 74 | middleman-gh-pages (0.0.3) 75 | rake (> 0.9.3) 76 | middleman-livereload (3.3.4) 77 | em-websocket (~> 0.5.1) 78 | middleman-core (~> 3.2) 79 | rack-livereload (~> 0.3.15) 80 | middleman-sprockets (3.4.1) 81 | middleman-core (>= 3.3) 82 | sprockets (~> 2.12.1) 83 | sprockets-helpers (~> 1.1.0) 84 | sprockets-sass (~> 1.3.0) 85 | middleman-syntax (2.0.0) 86 | middleman-core (~> 3.2) 87 | rouge (~> 1.0) 88 | minitest (5.5.1) 89 | multi_json (1.10.1) 90 | padrino-helpers (0.12.4) 91 | i18n (~> 0.6, >= 0.6.7) 92 | padrino-support (= 0.12.4) 93 | tilt (~> 1.4.1) 94 | padrino-support (0.12.4) 95 | activesupport (>= 3.1) 96 | rack (1.6.0) 97 | rack-livereload (0.3.15) 98 | rack 99 | rack-test (0.6.3) 100 | rack (>= 1.0) 101 | rake (10.4.2) 102 | rb-fsevent (0.9.4) 103 | rb-inotify (0.9.5) 104 | ffi (>= 0.5.0) 105 | redcarpet (3.2.2) 106 | ref (1.0.5) 107 | rouge (1.7.2) 108 | ruby18_source_location (0.2) 109 | sass (3.4.9) 110 | sprockets (2.12.3) 111 | hike (~> 1.2) 112 | multi_json (~> 1.0) 113 | rack (~> 1.0) 114 | tilt (~> 1.1, != 1.3.0) 115 | sprockets-helpers (1.1.0) 116 | sprockets (~> 2.0) 117 | sprockets-sass (1.3.1) 118 | sprockets (~> 2.0) 119 | tilt (~> 1.1) 120 | therubyracer (0.12.1) 121 | libv8 (~> 3.16.14.0) 122 | ref 123 | thor (0.19.1) 124 | thread_safe (0.3.4) 125 | tilt (1.4.1) 126 | timers (4.0.1) 127 | hitimes 128 | tzinfo (1.2.2) 129 | thread_safe (~> 0.1) 130 | uber (0.0.13) 131 | uglifier (2.7.0) 132 | execjs (>= 0.3.0) 133 | json (>= 1.8.0) 134 | 135 | PLATFORMS 136 | ruby 137 | 138 | DEPENDENCIES 139 | middleman (~> 3.3.0) 140 | middleman-gh-pages 141 | middleman-livereload (~> 3.3.0) 142 | middleman-syntax 143 | rake (~> 10.4.0) 144 | redcarpet (~> 3.2.1) 145 | rouge (= 1.7.2) 146 | ruby18_source_location 147 | therubyracer 148 | wdm (~> 0.1.0) 149 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # api-docs 2 | 3 | nasa/api-docs repository contains the front-end for http://nasa.github.io/api-docs/. This site will be CNAME mapped to 4 | api.nasa.gov 5 | 6 | This project will contain API developer pages for available NASA public APIs and will additionally house web components to allow 7 | NASA branded API pages to be integrated with the GSA api.data.gov system. 8 | 9 | POC: 10 | Jason Duley jason.duley@nasa.gov 11 | Dan Hammer daniel.s.hammer@nasa.gov 12 | 13 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'middleman-gh-pages' 2 | 3 | task :default => [:build] 4 | -------------------------------------------------------------------------------- /config.rb: -------------------------------------------------------------------------------- 1 | set :css_dir, 'stylesheets' 2 | 3 | set :js_dir, 'javascripts' 4 | 5 | set :images_dir, 'images' 6 | 7 | set :fonts_dir, 'fonts' 8 | 9 | set :markdown_engine, :redcarpet 10 | 11 | set :markdown, :fenced_code_blocks => true, :smartypants => true, :disable_indented_code_blocks => true, :prettify => true, :tables => true, :with_toc_data => true, :no_intra_emphasis => true 12 | 13 | # Activate the syntax highlighter 14 | activate :syntax 15 | 16 | # This is needed for Github pages, since they're hosted on a subdomain 17 | activate :relative_assets 18 | set :relative_links, true 19 | 20 | # Build-specific configuration 21 | configure :build do 22 | # For example, change the Compass output style for deployment 23 | activate :minify_css 24 | 25 | # Minify Javascript on build 26 | activate :minify_javascript 27 | 28 | # Enable cache buster 29 | # activate :asset_hash 30 | 31 | # Use relative URLs 32 | # activate :relative_assets 33 | 34 | # Or use a different image path 35 | # set :http_prefix, "/Content/images/" 36 | end 37 | 38 | -------------------------------------------------------------------------------- /meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "api-docs", 3 | "visibility": "public", 4 | "type": "GIT", 5 | "description": "repository to host api.nasa.gov website and associated API documentation.", 6 | "url": "https://github.com/nasa/api-docs", 7 | "repo": "nasa/api-docs", 8 | "missions":["OCIO", "GSA"], 9 | "categories": ["CTOF2F", "NASA"], 10 | "languages": ["Javascript", "HTML", "CSS", "Python"], 11 | "operating_systems": ["Linux", "Windows", "Unix", "Mac"], 12 | "poc": "Jason Duley", 13 | "poc_mbox": "jason.j.duley@nasa.gov", 14 | "license": "NASA Open Source Agreement Version 1.3", 15 | "software_types": ["website", "front-end", "gh-pages", "API"] 16 | } 17 | -------------------------------------------------------------------------------- /source/fonts/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpaceRocks/api-docs/dd8e393f0e201199ff00dd3c02ae8a1839822cbc/source/fonts/icomoon.eot -------------------------------------------------------------------------------- /source/fonts/icomoon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /source/fonts/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpaceRocks/api-docs/dd8e393f0e201199ff00dd3c02ae8a1839822cbc/source/fonts/icomoon.ttf -------------------------------------------------------------------------------- /source/fonts/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpaceRocks/api-docs/dd8e393f0e201199ff00dd3c02ae8a1839822cbc/source/fonts/icomoon.woff -------------------------------------------------------------------------------- /source/images/apod.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpaceRocks/api-docs/dd8e393f0e201199ff00dd3c02ae8a1839822cbc/source/images/apod.jpg -------------------------------------------------------------------------------- /source/images/earth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpaceRocks/api-docs/dd8e393f0e201199ff00dd3c02ae8a1839822cbc/source/images/earth.png -------------------------------------------------------------------------------- /source/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpaceRocks/api-docs/dd8e393f0e201199ff00dd3c02ae8a1839822cbc/source/images/logo.png -------------------------------------------------------------------------------- /source/images/mars.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpaceRocks/api-docs/dd8e393f0e201199ff00dd3c02ae8a1839822cbc/source/images/mars.jpg -------------------------------------------------------------------------------- /source/images/navbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpaceRocks/api-docs/dd8e393f0e201199ff00dd3c02ae8a1839822cbc/source/images/navbar.png -------------------------------------------------------------------------------- /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! Slown 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. -------------------------------------------------------------------------------- /source/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: API Reference 3 | 4 | toc_footers: 5 | - Sign Up for a Developer Key 6 | 7 | search: true 8 | --- 9 | 10 | # Introduction 11 | 12 | NASA has **the best** data. Way better than NOAA. Most visitors to [nasa.gov](https://www.nasa.gov) websites are looking for images and videos. The objective of this API is to make NASA data, especially imagery, emminently accessible to application developers. The [api.nasa.gov] index is growing. These endpoints are just a sample of the endpoints that will soon be available. Stay tuned. In the meantime, if you have any suggestions (either about the APIs or documentation) please submit an issue at the [open repository for this documentation site](https://github.com/nasa/api-docs). 13 | 14 | # Apply for an API Key 15 | 16 | # Authentication 17 | 18 | **You do not need to authenticate** in order to explore the NASA data. However, if you will be intensively using the APIs to, say, support a mobile application, then you should sign up for an [api.data.gov developer key](https://api.data.gov/signup). 19 | 20 | ## Web Service Rate Limits 21 | 22 | Limits are placed on the number of API requests you may make using your API key. Rate limits may vary by service, but the defaults are: 23 | 24 | - Hourly Limit: 1,000 requests per hour 25 | 26 | For each API key, these limits are applied across all api.data.gov API requests. Exceeding these limits will lead to your API key being temporarily blocked from making further requests. The block will automatically be lifted by waiting an hour. If you need higher rate limits, contact us. 27 | 28 | ## DEMO_KEY Rate Limits 29 | In documentation examples, the special DEMO_KEY api key is used. This API key can be used for initially exploring APIs prior to signing up, but it has much lower rate limits, so you're encouraged to signup for your own API key if you plan to use the API (signup is quick and easy). The rate limits for the DEMO_KEY are: 30 | 31 | - Hourly Limit: 30 requests per IP address per hour 32 | - Daily Limit: 50 requests per IP address per day 33 | 34 | ## How Do I See My Current Usage? 35 | 36 | Your can check your current rate limit and usage details by inspecting the `X-RateLimit-Limit` and `X-RateLimit-Remaining` HTTP headers that are returned on every API response. For example, if an API has the default hourly limit of 1,000 request, after making 2 requests, you will receive this HTTP header in the response of the second request: 37 | 38 | `X-RateLimit-Remaining: 998` 39 | 40 | The hourly counters for your API key reset on a rolling basis. 41 | 42 | **Example**: If you made 500 requests at 10:15AM and 500 requests at 10:25AM, your API key would become temporarily blocked. This temporary block of your API key would cease at 11:15AM, at which point you could make 500 requests. At 11:25AM, you could then make another 500 requests. 43 | 44 | 45 | 48 | 49 | # Earth 50 | 51 | A recent industry [report](https://www.fgdc.gov/ngac/meetings/december-2014/ngac-landsat-economic-value-paper-2014-update.pdf) estimates that total annual value of $2.19 billion, far exceeding the multi-year total cost of building, launching, and managing Landsat satellites and sensors. The value is derived from consumer *use* of the data. There is no inherent value in idle data. The objective of this endpoint is to unlock the significant public investment in earth observation data. This open and documented API should dramatically reduce the transaction costs to engage with the imagery.The API is powered by Google Earth Engine, and currently only supports pan-sharpened Landsat 8 imagery. 52 | 53 | **Example image:** 54 | 55 | ![](../images/earth.png) 56 | 57 | Imagine the possibilities associated with this imagery, like [monitoring deforestation at 15-meter resolution](https://www.globalforestwatch.org) or assessing the damage from natural disasters. If you discover any cool applications, [please let us know](mailto:daniel.s.hammer@nasa.gov) so that we can showcase them on [open.nasa.gov](https://open.nasa.gov). 58 | 59 | ## Imagery 60 | 61 | This endpoint retrieves the Landsat 8 image for the supplied location and 62 | date. The response will include the date and URL to the image that is closest to the supplied date. The requested resource may not be available for the *exact* date in the request. You can retrieve a list of available resources through the [assets endpoint](/#assets). 63 | 64 | The cloud score is an optional calculation that returns the percentage of the queried image that is covered by clouds. If `False` is supplied to the `cloud_score` parameter, then no keypair is returned. If `True` is supplied, then a keypair will always be returned, even if the backend algorithm is not able to calculate a score. Note that this is a rough calculation, mainly used to filter out exceedingly cloudy images. 65 | 66 | ### HTTP Request 67 | 68 | `GET https://api.data.gov/nasa/planetary/earth/imagery` 69 | 70 | ### Query Parameters 71 | 72 | Parameter | Type | Default | Description 73 | --------- | --------- | ------- | ----------- 74 | lat | float | n/a | Latitude 75 | lon | float | n/a | Longitude 76 | dim | float | 0.025 | width and height of image in degrees 77 | date | YYYY-MM-DD | *today* | date of image; if not supplied, then the most recent image (i.e., closest to today) is returned 78 | cloud_score | bool | False | calculate the percentage of the image covered by clouds 79 | api_key | string | DEMO_KEY | api.data.gov key for expanded usage 80 | 81 | ### Example query 82 | [`https://api.data.gov/nasa/planetary/earth/imagery?lon=100.75&lat=1.5&date=2014-02-01&cloud_score=True&api_key=DEMO_KEY`](https://api.data.gov/nasa/planetary/earth/imagery?lon=100.75&lat=1.5&date=2014-02-01&cloud_score=True&api_key=DEMO_KEY) 83 | 84 | 87 | 88 | ## Assets 89 | 90 | Hey, Charlie, when was the last time a NASA image was taken of my house? This endpoint retrieves the date-times and asset names for available imagery for a supplied location. The satellite passes over each point on earth roughly once every sixteen days. [This is an amazing visualization](http://earthobservatory.nasa.gov/Features/LandsatBigData/) of the acquisition pattern for Landsat 8 imagery. The objective of this endpoint is primarily to support the use of the [imagery endpoint](/#imagery). 91 | 92 | ### HTTP Request 93 | 94 | `GET https://api.data.gov/nasa/planetary/earth/assets` 95 | 96 | ### Query Parameters 97 | 98 | Parameter | Type | Default | Description 99 | --------- | --------- | ------- | ----------- 100 | lat | float | n/a | Latitude 101 | lon | float | n/a | Longitude 102 | begin | YYYY-MM-DD | n/a | beginning of date range 103 | end | YYYY-MM-DD | *today* | end of date range 104 | api_key | string | DEMO_KEY | api.data.gov key for expanded usage 105 | 106 | ### Example query 107 | [`https://api.data.gov/nasa/planetary/earth/assets?lon=100.75&lat=1.5&begin=2014-02-01&api_key=DEMO_KEY`](https://api.data.gov/nasa/planetary/earth/assets?lon=100.75&lat=1.5&begin=2014-02-01&api_key=DEMO_KEY) 108 | 109 | 110 | # APOD 111 | 112 | One of the most popular websites at NASA is the [Astronomy Picture of the Day](http://apod.nasa.gov/apod/astropix.html). In fact, this website is one of the [most popular websites](https://analytics.usa.gov/demo/) across all federal agencies. It has the popular appeal of a Justin Bieber video. This endpoint structures the APOD imagery and associated metadata so that it can be repurposed for other applications. In addition, if the `concept_tags` parameter is set to `True`, then keywords derived from the image explanation are returned. These keywords could be used as auto-generated hashtags for twitter or instagram feeds; but generally help with discoverability of relevant imagery. 113 | 114 | **Example image:** 115 | 116 | ![](../images/apod.jpg) 117 | 118 | ### HTTP Request 119 | 120 | `GET https://api.data.gov/nasa/planetary/apod` 121 | 122 | ### Query Parameters 123 | 124 | Parameter | Type | Default | Description 125 | --------- | --------- | ------- | ----------- 126 | date | YYYY-MM-DD | *today* | The date of the APOD image to retrieve 127 | concept_tags | bool | False | Return an ordered dictionary of concepts from the APOD explanation 128 | api_key | string | DEMO_KEY | api.data.gov key for expanded usage 129 | 130 | ### Example query 131 | [`https://api.data.gov/nasa/planetary/apod?concept_tags=True&api_key=DEMO_KEY`](https://api.data.gov/nasa/planetary/apod?concept_tags=True&api_key=DEMO_KEY) 132 | 133 | # Earth temperature anomalies 134 | 135 | There is no doubt that, on average, the earth is warming. However, the warming is spatially heterogenous. How much warmer (or cooler) is your hometown? This endpoint reports local temperature anomalies from the [Goddard Institute for Space Studies Surface Temperature Analysis](http://data.giss.nasa.gov/gistemp/) via the [New Scientist](http://www.newscientist.com/) web application to [explore global temperature anomalies](http://warmingworld.newscientistapps.com/). This endpoint restructures the query and response to correspond to other APIs on api.nasa.gov. The developer supplies a location and date range, and the returned object is a list of dictionaries that is ready for visualization in the [d3 framework](http://d3js.org/). 136 | 137 | ## Address 138 | 139 | The location can be specified as an address string. 140 | 141 | ### HTTP Request 142 | 143 | `GET https://api.data.gov/nasa/planetary/earth/temperature/address` 144 | 145 | ### Query Parameters 146 | 147 | Parameter | Type | Default | Description 148 | --------- | --------- | ------- | ----------- 149 | text | string | n/a | Address string 150 | begin | int | 1880 | beginning year for date range, inclusive 151 | end | int | 2014 | end year for date range, inclusive 152 | api_key | string | DEMO_KEY | api.data.gov key for expanded usage 153 | 154 | ### Example query 155 | [`https://api.data.gov/nasa/planetary/earth/temperature/address?text=1800 F Street, NW, Washington DC&begin=1990`](https://api.data.gov/nasa/planetary/earth/temperature/address?text=1800 F Street, NW, Washington DC&begin=1990&api_key=DEMO_KEY) 156 | 157 | ## Coordinates 158 | 159 | Alternatively, you can supply the precise latitude and longitude as the location. 160 | 161 | ### HTTP Request 162 | 163 | `GET https://api.data.gov/planetary/earth/temperature/coords` 164 | 165 | ### Query Parameters 166 | 167 | Parameter | Type | Default | Description 168 | --------- | --------- | ------- | ----------- 169 | lat | float | n/a | Latitude 170 | lon | float | n/a | Longitude 171 | begin | int | 1880 | beginning year for date range, inclusive 172 | end | int | 2014 | end year for date range, inclusive 173 | api_key | string | DEMO_KEY | api.data.gov key for expanded usage 174 | 175 | ### Example query 176 | [`https://api.data.gov/nasa/planetary/earth/temperature/coords?lat=100.3&lon=1.6&begin=1990&end=2005&api_key=DEMO_KEY`](https://api.data.gov/nasa/planetary/earth/temperature/coords?lat=100.3&lon=1.6&begin=1990&end=2005&api_key=DEMO_KEY) 177 | 178 | # Patents 179 | 180 | The NASA patent portfolio is available to benefit US citizens. Through partnerships and licensing agreements with industry, these patents ensure that NASA's investments in pioneering research find secondary uses that benefit the economy, create jobs, and improve quality of life. This endpoint provides structured, searchable developer access to NASA's patents that have been curated to support technology transfer. 181 | 182 | ### HTTP Request 183 | 184 | `GET https://api.data.gov/patents` 185 | 186 | ### Query Parameters 187 | 188 | Parameter | Type | Default | Description 189 | --------- | --------- | ------- | ----------- 190 | query | string | None | Search text to filter results 191 | concept_tags | bool | False | Return an ordered dictionary of concepts from the patent abstract 192 | limit | int | *all* | number of patents to return 193 | api_key | string | DEMO_KEY | api.data.gov key for expanded usage 194 | 195 | ### Example query 196 | [`https://api.data.gov/nasa/patents/content?query=temperature&limit=5&api_key=DEMO_KEY`](https://api.data.gov/nasa/patents/content?query=temperature&limit=5&api_key=DEMO_KEY) 197 | 198 | -------------------------------------------------------------------------------- /source/javascripts/all.js: -------------------------------------------------------------------------------- 1 | //= require_tree ./lib 2 | //= require_tree ./app 3 | -------------------------------------------------------------------------------- /source/javascripts/all_nosearch.js: -------------------------------------------------------------------------------- 1 | //= require_tree ./lib 2 | //= require_tree ./app 3 | //= stub ./app/search.js 4 | //= stub ./lib/lunr.js 5 | -------------------------------------------------------------------------------- /source/javascripts/app/lang.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2008-2013 Concur Technologies, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | not use this file except in compliance with the License. You may obtain 6 | a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | License for the specific language governing permissions and limitations 14 | under the License. 15 | */ 16 | (function (global) { 17 | var languages = []; 18 | 19 | global.setupLanguages = setupLanguages; 20 | global.activateLanguage = activateLanguage; 21 | 22 | function activateLanguage(language) { 23 | if (!language) return; 24 | if (language === "") return; 25 | 26 | $(".lang-selector a").removeClass('active'); 27 | $(".lang-selector a[data-language-name='" + language + "']").addClass('active'); 28 | for (var i=0; i < languages.length; i++) { 29 | $(".highlight." + languages[i]).parent().hide(); 30 | } 31 | $(".highlight." + language).parent().show(); 32 | 33 | global.toc.calculateHeights(); 34 | 35 | // scroll to the new location of the position 36 | if ($(window.location.hash).get(0)) { 37 | $(window.location.hash).get(0).scrollIntoView(true); 38 | } 39 | } 40 | 41 | // if a button is clicked, add the state to the history 42 | function pushURL(language) { 43 | if (!history) { return; } 44 | var hash = window.location.hash; 45 | if (hash) { 46 | hash = hash.replace(/^#+/, ''); 47 | } 48 | history.pushState({}, '', '?' + language + '#' + hash); 49 | 50 | // save language as next default 51 | localStorage.setItem("language", language); 52 | } 53 | 54 | function setupLanguages(l) { 55 | var currentLanguage = l[0]; 56 | var defaultLanguage = localStorage.getItem("language"); 57 | 58 | languages = l; 59 | 60 | if ((location.search.substr(1) !== "") && (jQuery.inArray(location.search.substr(1), languages)) != -1) { 61 | // the language is in the URL, so use that language! 62 | activateLanguage(location.search.substr(1)); 63 | 64 | localStorage.setItem("language", location.search.substr(1)); 65 | } else if ((defaultLanguage !== null) && (jQuery.inArray(defaultLanguage, languages) != -1)) { 66 | // the language was the last selected one saved in localstorage, so use that language! 67 | activateLanguage(defaultLanguage); 68 | } else { 69 | // no language selected, so use the default 70 | activateLanguage(languages[0]); 71 | } 72 | } 73 | 74 | // if we click on a language tab, activate that language 75 | $(function() { 76 | $(".lang-selector a").on("click", function() { 77 | var language = $(this).data("language-name"); 78 | pushURL(language); 79 | activateLanguage(language); 80 | return false; 81 | }); 82 | window.onpopstate = function(event) { 83 | activateLanguage(window.location.search.substr(1)); 84 | }; 85 | }); 86 | })(window); 87 | -------------------------------------------------------------------------------- /source/javascripts/app/search.js: -------------------------------------------------------------------------------- 1 | (function (global) { 2 | 3 | var $global = $(global); 4 | var content, darkBox, searchResults; 5 | var highlightOpts = { element: 'span', className: 'search-highlight' }; 6 | 7 | var index = new lunr.Index(); 8 | 9 | index.ref('id'); 10 | index.field('title', { boost: 10 }); 11 | index.field('body'); 12 | index.pipeline.add(lunr.trimmer, lunr.stopWordFilter); 13 | 14 | $(populate); 15 | $(bind); 16 | 17 | function populate() { 18 | $('h1, h2').each(function() { 19 | var title = $(this); 20 | var body = title.nextUntil('h1, h2'); 21 | index.add({ 22 | id: title.prop('id'), 23 | title: title.text(), 24 | body: body.text() 25 | }); 26 | }); 27 | } 28 | 29 | function bind() { 30 | content = $('.content'); 31 | darkBox = $('.dark-box'); 32 | searchResults = $('.search-results'); 33 | 34 | $('#input-search').on('keyup', search); 35 | } 36 | 37 | function search(event) { 38 | unhighlight(); 39 | searchResults.addClass('visible'); 40 | 41 | // ESC clears the field 42 | if (event.keyCode === 27) this.value = ''; 43 | 44 | if (this.value) { 45 | var results = index.search(this.value).filter(function(r) { 46 | return r.score > 0.0001; 47 | }); 48 | 49 | if (results.length) { 50 | searchResults.empty(); 51 | $.each(results, function (index, result) { 52 | searchResults.append("
  • " + $('#'+result.ref).text() + "
  • "); 53 | }); 54 | highlight.call(this); 55 | } else { 56 | searchResults.html('
  • '); 57 | $('.search-results li').text('No Results Found for "' + this.value + '"'); 58 | } 59 | } else { 60 | unhighlight(); 61 | searchResults.removeClass('visible'); 62 | } 63 | } 64 | 65 | function highlight() { 66 | if (this.value) content.highlight(this.value, highlightOpts); 67 | } 68 | 69 | function unhighlight() { 70 | content.unhighlight(highlightOpts); 71 | } 72 | 73 | })(window); 74 | -------------------------------------------------------------------------------- /source/javascripts/app/toc.js: -------------------------------------------------------------------------------- 1 | (function (global) { 2 | 3 | var closeToc = function() { 4 | $(".tocify-wrapper").removeClass('open'); 5 | $("#nav-button").removeClass('open'); 6 | }; 7 | 8 | var makeToc = function() { 9 | global.toc = $("#toc").tocify({ 10 | selectors: 'h1, h2', 11 | extendPage: false, 12 | theme: 'none', 13 | smoothScroll: false, 14 | showEffectSpeed: 0, 15 | hideEffectSpeed: 180, 16 | ignoreSelector: '.toc-ignore', 17 | highlightOffset: 60, 18 | scrollTo: -1, 19 | scrollHistory: true, 20 | hashGenerator: function (text, element) { 21 | return element.prop('id'); 22 | } 23 | }).data('toc-tocify'); 24 | 25 | $("#nav-button").click(function() { 26 | $(".tocify-wrapper").toggleClass('open'); 27 | $("#nav-button").toggleClass('open'); 28 | return false; 29 | }); 30 | 31 | $(".page-wrapper").click(closeToc); 32 | $(".tocify-item").click(closeToc); 33 | }; 34 | 35 | // Hack to make already open sections to start opened, 36 | // instead of displaying an ugly animation 37 | function animate () { 38 | setTimeout(function() { 39 | toc.setOption('showEffectSpeed', 180); 40 | }, 50); 41 | } 42 | 43 | $(makeToc); 44 | $(animate); 45 | 46 | })(window); 47 | 48 | -------------------------------------------------------------------------------- /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 | })(); -------------------------------------------------------------------------------- /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/javascripts/lib/jquery.tocify.js: -------------------------------------------------------------------------------- 1 | //= require ./jquery_ui 2 | /* jquery Tocify - v1.8.0 - 2013-09-16 3 | * http://www.gregfranko.com/jquery.tocify.js/ 4 | * Copyright (c) 2013 Greg Franko; Licensed MIT 5 | * Modified lightly by Robert Lord to fix a bug I found, 6 | * and also so it adds ids to headers 7 | * also because I want height caching, since the 8 | * height lookup for h1s and h2s was causing serious 9 | * lag spikes below 30 fps */ 10 | 11 | // Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic. I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE. 12 | (function(tocify) { 13 | 14 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 15 | "use strict"; 16 | 17 | // Calls the second IIFE and locally passes in the global jQuery, window, and document objects 18 | tocify(window.jQuery, window, document); 19 | 20 | } 21 | 22 | // Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable. The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set. All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript. 23 | (function($, window, document, undefined) { 24 | 25 | // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) 26 | "use strict"; 27 | 28 | var tocClassName = "tocify", 29 | tocClass = "." + tocClassName, 30 | tocFocusClassName = "tocify-focus", 31 | tocHoverClassName = "tocify-hover", 32 | hideTocClassName = "tocify-hide", 33 | hideTocClass = "." + hideTocClassName, 34 | headerClassName = "tocify-header", 35 | headerClass = "." + headerClassName, 36 | subheaderClassName = "tocify-subheader", 37 | subheaderClass = "." + subheaderClassName, 38 | itemClassName = "tocify-item", 39 | itemClass = "." + itemClassName, 40 | extendPageClassName = "tocify-extend-page", 41 | extendPageClass = "." + extendPageClassName; 42 | 43 | // Calling the jQueryUI Widget Factory Method 44 | $.widget("toc.tocify", { 45 | 46 | //Plugin version 47 | version: "1.8.0", 48 | 49 | // These options will be used as defaults 50 | options: { 51 | 52 | // **context**: Accepts String: Any jQuery selector 53 | // The container element that holds all of the elements used to generate the table of contents 54 | context: "body", 55 | 56 | // **ignoreSelector**: Accepts String: Any jQuery selector 57 | // A selector to any element that would be matched by selectors that you wish to be ignored 58 | ignoreSelector: null, 59 | 60 | // **selectors**: Accepts an Array of Strings: Any jQuery selectors 61 | // The element's used to generate the table of contents. The order is very important since it will determine the table of content's nesting structure 62 | selectors: "h1, h2, h3", 63 | 64 | // **showAndHide**: Accepts a boolean: true or false 65 | // Used to determine if elements should be shown and hidden 66 | showAndHide: true, 67 | 68 | // **showEffect**: Accepts String: "none", "fadeIn", "show", or "slideDown" 69 | // Used to display any of the table of contents nested items 70 | showEffect: "slideDown", 71 | 72 | // **showEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast" 73 | // The time duration of the show animation 74 | showEffectSpeed: "medium", 75 | 76 | // **hideEffect**: Accepts String: "none", "fadeOut", "hide", or "slideUp" 77 | // Used to hide any of the table of contents nested items 78 | hideEffect: "slideUp", 79 | 80 | // **hideEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast" 81 | // The time duration of the hide animation 82 | hideEffectSpeed: "medium", 83 | 84 | // **smoothScroll**: Accepts a boolean: true or false 85 | // Determines if a jQuery animation should be used to scroll to specific table of contents items on the page 86 | smoothScroll: true, 87 | 88 | // **smoothScrollSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast" 89 | // The time duration of the smoothScroll animation 90 | smoothScrollSpeed: "medium", 91 | 92 | // **scrollTo**: Accepts Number (pixels) 93 | // The amount of space between the top of page and the selected table of contents item after the page has been scrolled 94 | scrollTo: 0, 95 | 96 | // **showAndHideOnScroll**: Accepts a boolean: true or false 97 | // Determines if table of contents nested items should be shown and hidden while scrolling 98 | showAndHideOnScroll: true, 99 | 100 | // **highlightOnScroll**: Accepts a boolean: true or false 101 | // Determines if table of contents nested items should be highlighted (set to a different color) while scrolling 102 | highlightOnScroll: true, 103 | 104 | // **highlightOffset**: Accepts a number 105 | // The offset distance in pixels to trigger the next active table of contents item 106 | highlightOffset: 40, 107 | 108 | // **theme**: Accepts a string: "bootstrap", "jqueryui", or "none" 109 | // Determines if Twitter Bootstrap, jQueryUI, or Tocify classes should be added to the table of contents 110 | theme: "bootstrap", 111 | 112 | // **extendPage**: Accepts a boolean: true or false 113 | // If a user scrolls to the bottom of the page and the page is not tall enough to scroll to the last table of contents item, then the page height is increased 114 | extendPage: true, 115 | 116 | // **extendPageOffset**: Accepts a number: pixels 117 | // How close to the bottom of the page a user must scroll before the page is extended 118 | extendPageOffset: 100, 119 | 120 | // **history**: Accepts a boolean: true or false 121 | // Adds a hash to the page url to maintain history 122 | history: true, 123 | 124 | // **scrollHistory**: Accepts a boolean: true or false 125 | // Adds a hash to the page url, to maintain history, when scrolling to a TOC item 126 | scrollHistory: false, 127 | 128 | // **hashGenerator**: How the hash value (the anchor segment of the URL, following the 129 | // # character) will be generated. 130 | // 131 | // "compact" (default) - #CompressesEverythingTogether 132 | // "pretty" - #looks-like-a-nice-url-and-is-easily-readable 133 | // function(text, element){} - Your own hash generation function that accepts the text as an 134 | // argument, and returns the hash value. 135 | hashGenerator: "compact", 136 | 137 | // **highlightDefault**: Accepts a boolean: true or false 138 | // Set's the first TOC item as active if no other TOC item is active. 139 | highlightDefault: true 140 | 141 | }, 142 | 143 | // _Create 144 | // ------- 145 | // Constructs the plugin. Only called once. 146 | _create: function() { 147 | 148 | var self = this; 149 | 150 | self.tocifyWrapper = $('.tocify-wrapper'); 151 | self.extendPageScroll = true; 152 | 153 | // Internal array that keeps track of all TOC items (Helps to recognize if there are duplicate TOC item strings) 154 | self.items = []; 155 | 156 | // Generates the HTML for the dynamic table of contents 157 | self._generateToc(); 158 | 159 | // Caches heights and anchors 160 | self.cachedHeights = [], 161 | self.cachedAnchors = []; 162 | 163 | // Adds CSS classes to the newly generated table of contents HTML 164 | self._addCSSClasses(); 165 | 166 | self.webkit = (function() { 167 | 168 | for(var prop in window) { 169 | 170 | if(prop) { 171 | 172 | if(prop.toLowerCase().indexOf("webkit") !== -1) { 173 | 174 | return true; 175 | 176 | } 177 | 178 | } 179 | 180 | } 181 | 182 | return false; 183 | 184 | }()); 185 | 186 | // Adds jQuery event handlers to the newly generated table of contents 187 | self._setEventHandlers(); 188 | 189 | // Binding to the Window load event to make sure the correct scrollTop is calculated 190 | $(window).load(function() { 191 | 192 | // Sets the active TOC item 193 | self._setActiveElement(true); 194 | 195 | // Once all animations on the page are complete, this callback function will be called 196 | $("html, body").promise().done(function() { 197 | 198 | setTimeout(function() { 199 | 200 | self.extendPageScroll = false; 201 | 202 | },0); 203 | 204 | }); 205 | 206 | }); 207 | 208 | }, 209 | 210 | // _generateToc 211 | // ------------ 212 | // Generates the HTML for the dynamic table of contents 213 | _generateToc: function() { 214 | 215 | // _Local variables_ 216 | 217 | // Stores the plugin context in the self variable 218 | var self = this, 219 | 220 | // All of the HTML tags found within the context provided (i.e. body) that match the top level jQuery selector above 221 | firstElem, 222 | 223 | // Instantiated variable that will store the top level newly created unordered list DOM element 224 | ul, 225 | ignoreSelector = self.options.ignoreSelector; 226 | 227 | // If the selectors option has a comma within the string 228 | if(this.options.selectors.indexOf(",") !== -1) { 229 | 230 | // Grabs the first selector from the string 231 | firstElem = $(this.options.context).find(this.options.selectors.replace(/ /g,"").substr(0, this.options.selectors.indexOf(","))); 232 | 233 | } 234 | 235 | // If the selectors option does not have a comman within the string 236 | else { 237 | 238 | // Grabs the first selector from the string and makes sure there are no spaces 239 | firstElem = $(this.options.context).find(this.options.selectors.replace(/ /g,"")); 240 | 241 | } 242 | 243 | if(!firstElem.length) { 244 | 245 | self.element.addClass(hideTocClassName); 246 | 247 | return; 248 | 249 | } 250 | 251 | self.element.addClass(tocClassName); 252 | 253 | // Loops through each top level selector 254 | firstElem.each(function(index) { 255 | 256 | //If the element matches the ignoreSelector then we skip it 257 | if($(this).is(ignoreSelector)) { 258 | return; 259 | } 260 | 261 | // Creates an unordered list HTML element and adds a dynamic ID and standard class name 262 | ul = $("