├── .ruby-version ├── source ├── fonts │ ├── slate.eot │ ├── slate.ttf │ ├── slate.woff │ ├── slate.woff2 │ └── slate.svg ├── images │ ├── logo.png │ ├── lois.png │ ├── peter.png │ ├── chrome.png │ ├── navbar.png │ ├── safari.png │ └── example_spreadsheet.png ├── javascripts │ ├── all_nosearch.js │ ├── all.js │ ├── lib │ │ ├── _gtm.js │ │ ├── _jquery.highlight.js │ │ ├── _energize.js │ │ ├── _imagesloaded.min.js │ │ ├── _ahoy.js │ │ └── _jquery_ui.js │ └── app │ │ ├── _toc.js │ │ ├── _search.js │ │ └── _lang.js ├── includes │ ├── _core.md │ ├── _introduction.md │ ├── _other.md │ ├── _snippet.md │ └── core │ │ ├── _update.md │ │ ├── _delete.md │ │ ├── _create.md │ │ └── _read.md ├── index.html.md ├── stylesheets │ ├── _icon-font.scss │ ├── print.css.scss │ ├── _variables.scss │ ├── _normalize.scss │ └── screen.css.scss └── layouts │ └── layout.erb ├── deploy_production.sh ├── .travis.yml ├── Gemfile ├── .gitignore ├── lib └── multilang.rb ├── LICENSE ├── config.rb ├── Vagrantfile ├── README.md ├── CHANGELOG.md ├── Gemfile.lock └── font-selection.json /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.3.0 2 | -------------------------------------------------------------------------------- /source/fonts/slate.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sheetdb/sheetsu-docs/HEAD/source/fonts/slate.eot -------------------------------------------------------------------------------- /source/fonts/slate.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sheetdb/sheetsu-docs/HEAD/source/fonts/slate.ttf -------------------------------------------------------------------------------- /source/fonts/slate.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sheetdb/sheetsu-docs/HEAD/source/fonts/slate.woff -------------------------------------------------------------------------------- /source/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sheetdb/sheetsu-docs/HEAD/source/images/logo.png -------------------------------------------------------------------------------- /source/images/lois.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sheetdb/sheetsu-docs/HEAD/source/images/lois.png -------------------------------------------------------------------------------- /source/images/peter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sheetdb/sheetsu-docs/HEAD/source/images/peter.png -------------------------------------------------------------------------------- /source/fonts/slate.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sheetdb/sheetsu-docs/HEAD/source/fonts/slate.woff2 -------------------------------------------------------------------------------- /source/images/chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sheetdb/sheetsu-docs/HEAD/source/images/chrome.png -------------------------------------------------------------------------------- /source/images/navbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sheetdb/sheetsu-docs/HEAD/source/images/navbar.png -------------------------------------------------------------------------------- /source/images/safari.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sheetdb/sheetsu-docs/HEAD/source/images/safari.png -------------------------------------------------------------------------------- /deploy_production.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | scp -r build/* deployer@docs.sheetsu.com:/home/deployer/docs.sheetsu.com 3 | -------------------------------------------------------------------------------- /source/images/example_spreadsheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sheetdb/sheetsu-docs/HEAD/source/images/example_spreadsheet.png -------------------------------------------------------------------------------- /source/javascripts/all_nosearch.js: -------------------------------------------------------------------------------- 1 | //= require ./lib/_gtm 2 | //= require ./lib/_energize 3 | //= require ./app/_lang 4 | //= require ./app/_toc 5 | //= require ./lib/_ahoy 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: ruby 4 | 5 | rvm: 6 | - 2.2.5 7 | - 2.3.3 8 | - 2.4.0 9 | 10 | cache: bundler 11 | script: bundle exec middleman build 12 | -------------------------------------------------------------------------------- /source/includes/_core.md: -------------------------------------------------------------------------------- 1 | # Core 2 | Edit on GitHub 3 | -------------------------------------------------------------------------------- /source/javascripts/all.js: -------------------------------------------------------------------------------- 1 | //= require ./lib/_gtm 2 | //= require ./lib/_energize 3 | //= require ./app/_lang 4 | //= require ./app/_search 5 | //= require ./app/_toc 6 | //= require ./lib/_ahoy 7 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | ruby '>= 2.3.1' 2 | 3 | source 'https://rubygems.org' 4 | 5 | # Middleman 6 | gem 'middleman', '~>4.2.1' 7 | gem 'middleman-syntax', '~> 3.0.0' 8 | gem 'middleman-autoprefixer', '~> 2.7.0' 9 | gem "middleman-sprockets", "~> 4.1.0" 10 | gem 'rouge', '~> 2.0.5' 11 | gem 'redcarpet', '~> 3.4.0' 12 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /source/javascripts/lib/_gtm.js: -------------------------------------------------------------------------------- 1 | (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': 2 | new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], 3 | j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 4 | 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); 5 | })(window,document,'script','dataLayer','GTM-PFW66ZF'); 6 | -------------------------------------------------------------------------------- /lib/multilang.rb: -------------------------------------------------------------------------------- 1 | module Multilang 2 | def block_code(code, full_lang_name) 3 | parts = full_lang_name.split('--') 4 | rouge_lang_name = parts[0] || "" 5 | super(code, rouge_lang_name).sub("highlight #{rouge_lang_name}") do |match| 6 | match + " tab-" + full_lang_name 7 | end 8 | end 9 | end 10 | 11 | require 'middleman-core/renderers/redcarpet' 12 | Middleman::Renderers::MiddlemanRedcarpetHTML.send :include, Multilang 13 | -------------------------------------------------------------------------------- /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/index.html.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Sheetsu Documentation 3 | 4 | language_tabs: 5 | - shell: cURL 6 | - xml: HTML Snippet 7 | - ruby: Ruby 8 | - javascript--node: Node 9 | - html--javascript: JavaScript Web Client 10 | - python: Python 11 | - php: PHP 12 | - javascript--jquery: JQuery 13 | - csharp: C# 14 | - swift: Swift 15 | - r: R 16 | - jsx: React 17 | 18 | toc_footers: 19 | - Dashboard 20 | - Pricing 21 | 22 | search: true 23 | 24 | includes: 25 | - introduction 26 | - core 27 | - core/read 28 | - core/create 29 | - core/update 30 | - core/delete 31 | - snippet 32 | - other 33 | --- 34 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | ready do 21 | require './lib/multilang.rb' 22 | end 23 | 24 | activate :sprockets 25 | 26 | activate :autoprefixer do |config| 27 | config.browsers = ['last 2 version', 'Firefox ESR'] 28 | config.cascade = false 29 | config.inline = true 30 | end 31 | 32 | # Github pages require relative links 33 | activate :relative_assets 34 | set :relative_links, true 35 | 36 | # Build Configuration 37 | configure :build do 38 | # If you're having trouble with Middleman hanging, commenting 39 | # out the following two lines has been known to help 40 | activate :minify_css 41 | activate :minify_javascript 42 | # activate :relative_assets 43 | # activate :asset_hash 44 | # activate :gzip 45 | end 46 | 47 | # Deploy Configuration 48 | # If you want Middleman to listen on a different port, you can set that below 49 | set :port, 4567 50 | -------------------------------------------------------------------------------- /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 --latency=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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Official [Sheetsu.com](https://sheetsu.com) documentation 2 | 3 | Welcome to the official API documentation for Sheetsu.com, Google Spreadsheets as a REST APIs. We're happy you are here! 4 | 5 | Feel free to check out the [live documentation page](https://docs.sheetsu.com). 6 | 7 | If you'd like to make an edit to any of these pages, please [submit a pull request](https://github.com/sheetsu/docs/pulls). Take a look below, for instructions how to run this page locally. We use [Slate](https://lord.github.io/slate/) to power our docs. 8 | 9 | Getting Started 10 | ------------------------------ 11 | 12 | ### Prerequisites 13 | 14 | You're going to need: 15 | 16 | - **Linux or OS X** — Windows may work, but is unsupported. 17 | - **Ruby, version 2.2.5 or newer** 18 | - **Bundler** — If Ruby is already installed, but the `bundle` command doesn't work, just run `gem install bundler` in a terminal. 19 | 20 | ### Getting Set Up 21 | 22 | 1. Fork this repository on Github. 23 | 2. Clone *your forked repository* (not our original one) to your hard drive with `git clone https://github.com/YOURUSERNAME/docs.git` 24 | 3. `cd docs` 25 | 4. Initialize and start Slate. You can either do this locally, or with Vagrant: 26 | 27 | ```shell 28 | # either run this to run locally 29 | bundle install 30 | bundle exec middleman server 31 | 32 | # OR run this to run with vagrant 33 | vagrant up 34 | ``` 35 | 36 | You can now see the docs at http://localhost:4567. Whoa! That was fast! 37 | 38 | 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). 39 | 40 | If you'd prefer to use Docker, instructions are available [in the wiki](https://github.com/lord/slate/wiki/Docker). 41 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Version 1.5.0 4 | 5 | *February 23, 2017* 6 | 7 | - Add [multiple tabs per programming language](https://github.com/lord/slate/wiki/Multiple-language-tabs-per-programming-language) feature 8 | - Upgrade Middleman to add Ruby 1.4.0 compatibility 9 | - Switch default code highlighting color scheme to better highlight JSON 10 | - Various small typo and bug fixes 11 | 12 | ## Version 1.4.0 13 | 14 | *November 24, 2016* 15 | 16 | - Upgrade Middleman and Rouge gems, should hopefully solve a number of bugs 17 | - Update some links in README 18 | - Fix broken Vagrant startup script 19 | - Fix some problems with deploy.sh help message 20 | - Fix bug with language tabs not hiding properly if no error 21 | - Add `!default` to SASS variables 22 | - Fix bug with logo margin 23 | - Bump tested Ruby versions in .travis.yml 24 | 25 | ## Version 1.3.3 26 | 27 | *June 11, 2016* 28 | 29 | Documentation and example changes. 30 | 31 | ## Version 1.3.2 32 | 33 | *February 3, 2016* 34 | 35 | A small bugfix for slightly incorrect background colors on code samples in some cases. 36 | 37 | ## Version 1.3.1 38 | 39 | *January 31, 2016* 40 | 41 | A small bugfix for incorrect whitespace in code blocks. 42 | 43 | ## Version 1.3 44 | 45 | *January 27, 2016* 46 | 47 | We've upgraded Middleman and a number of other dependencies, which should fix quite a few bugs. 48 | 49 | 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. 50 | 51 | ## Version 1.2 52 | 53 | *June 20, 2015* 54 | 55 | **Fixes:** 56 | 57 | - Remove crash on invalid languages 58 | - Update Tocify to scroll to the highlighted header in the Table of Contents 59 | - Fix variable leak and update search algorithms 60 | - Update Python examples to be valid Python 61 | - Update gems 62 | - More misc. bugfixes of Javascript errors 63 | - Add Dockerfile 64 | - Remove unused gems 65 | - Optimize images, fonts, and generated asset files 66 | - Add chinese font support 67 | - Remove RedCarpet header ID patch 68 | - Update language tabs to not disturb existing query strings 69 | 70 | ## Version 1.1 71 | 72 | *July 27, 2014* 73 | 74 | **Fixes:** 75 | 76 | - Finally, a fix for the redcarpet upgrade bug 77 | 78 | ## Version 1.0 79 | 80 | *July 2, 2014* 81 | 82 | [View Issues](https://github.com/tripit/slate/issues?milestone=1&state=closed) 83 | 84 | **Features:** 85 | 86 | - Responsive designs for phones and tablets 87 | - Started tagging versions 88 | 89 | **Fixes:** 90 | 91 | - Fixed 'unrecognized expression' error 92 | - Fixed #undefined hash bug 93 | - Fixed bug where the current language tab would be unselected 94 | - Fixed bug where tocify wouldn't highlight the current section while searching 95 | - Fixed bug where ids of header tags would have special characters that caused problems 96 | - Updated layout so that pages with disabled search wouldn't load search.js 97 | - Cleaned up Javascript 98 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | activesupport (5.0.6) 5 | concurrent-ruby (~> 1.0, >= 1.0.2) 6 | i18n (~> 0.7) 7 | minitest (~> 5.1) 8 | tzinfo (~> 1.1) 9 | addressable (2.5.2) 10 | public_suffix (>= 2.0.2, < 4.0) 11 | autoprefixer-rails (6.7.7.2) 12 | execjs 13 | backports (3.10.3) 14 | coffee-script (2.4.1) 15 | coffee-script-source 16 | execjs 17 | coffee-script-source (1.12.2) 18 | compass-import-once (1.0.5) 19 | sass (>= 3.2, < 3.5) 20 | concurrent-ruby (1.0.5) 21 | contracts (0.13.0) 22 | dotenv (2.2.1) 23 | erubis (2.7.0) 24 | execjs (2.7.0) 25 | fast_blank (1.0.0) 26 | fastimage (2.1.0) 27 | ffi (1.9.18) 28 | haml (5.0.4) 29 | temple (>= 0.8.0) 30 | tilt 31 | hamster (3.0.0) 32 | concurrent-ruby (~> 1.0) 33 | hashie (3.5.6) 34 | i18n (0.7.0) 35 | kramdown (1.15.0) 36 | listen (3.0.8) 37 | rb-fsevent (~> 0.9, >= 0.9.4) 38 | rb-inotify (~> 0.9, >= 0.9.7) 39 | memoist (0.16.0) 40 | middleman (4.2.1) 41 | coffee-script (~> 2.2) 42 | compass-import-once (= 1.0.5) 43 | haml (>= 4.0.5) 44 | kramdown (~> 1.2) 45 | middleman-cli (= 4.2.1) 46 | middleman-core (= 4.2.1) 47 | sass (>= 3.4.0, < 4.0) 48 | middleman-autoprefixer (2.7.1) 49 | autoprefixer-rails (>= 6.5.2, < 7.0.0) 50 | middleman-core (>= 3.3.3) 51 | middleman-cli (4.2.1) 52 | thor (>= 0.17.0, < 2.0) 53 | middleman-core (4.2.1) 54 | activesupport (>= 4.2, < 5.1) 55 | addressable (~> 2.3) 56 | backports (~> 3.6) 57 | bundler (~> 1.1) 58 | contracts (~> 0.13.0) 59 | dotenv 60 | erubis 61 | execjs (~> 2.0) 62 | fast_blank 63 | fastimage (~> 2.0) 64 | hamster (~> 3.0) 65 | hashie (~> 3.4) 66 | i18n (~> 0.7.0) 67 | listen (~> 3.0.0) 68 | memoist (~> 0.14) 69 | padrino-helpers (~> 0.13.0) 70 | parallel 71 | rack (>= 1.4.5, < 3) 72 | sass (>= 3.4) 73 | servolux 74 | tilt (~> 2.0) 75 | uglifier (~> 3.0) 76 | middleman-sprockets (4.1.1) 77 | middleman-core (~> 4.0) 78 | sprockets (>= 3.0) 79 | middleman-syntax (3.0.0) 80 | middleman-core (>= 3.2) 81 | rouge (~> 2.0) 82 | minitest (5.10.3) 83 | padrino-helpers (0.13.3.4) 84 | i18n (~> 0.6, >= 0.6.7) 85 | padrino-support (= 0.13.3.4) 86 | tilt (>= 1.4.1, < 3) 87 | padrino-support (0.13.3.4) 88 | activesupport (>= 3.1) 89 | parallel (1.12.0) 90 | public_suffix (3.0.1) 91 | rack (2.0.3) 92 | rb-fsevent (0.10.2) 93 | rb-inotify (0.9.10) 94 | ffi (>= 0.5.0, < 2) 95 | redcarpet (3.4.0) 96 | rouge (2.0.7) 97 | sass (3.4.25) 98 | servolux (0.13.0) 99 | sprockets (3.7.1) 100 | concurrent-ruby (~> 1.0) 101 | rack (> 1, < 3) 102 | temple (0.8.0) 103 | thor (0.20.0) 104 | thread_safe (0.3.6) 105 | tilt (2.0.8) 106 | tzinfo (1.2.4) 107 | thread_safe (~> 0.1) 108 | uglifier (3.2.0) 109 | execjs (>= 0.3.0, < 3) 110 | 111 | PLATFORMS 112 | ruby 113 | 114 | DEPENDENCIES 115 | middleman (~> 4.2.1) 116 | middleman-autoprefixer (~> 2.7.0) 117 | middleman-sprockets (~> 4.1.0) 118 | middleman-syntax (~> 3.0.0) 119 | redcarpet (~> 3.4.0) 120 | rouge (~> 2.0.5) 121 | 122 | RUBY VERSION 123 | ruby 2.3.1p112 124 | 125 | BUNDLED WITH 126 | 1.16.0 127 | -------------------------------------------------------------------------------- /source/includes/_introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | Edit on GitHub 3 | 4 | # Welcome 5 | 6 | You can view code examples in the area on the right. You can switch the programming language with the tabs in the top right. We provide examples in cURL, Ruby and some of them with our Snippet - which is pure HTML. 7 | 8 | Follow @sheetsuhq on Twitter for latest updates and news. 9 | 10 | # SDKs & Client libraries 11 | 12 | ### Official libraries 13 | 14 | * Ruby: [https://github.com/sheetsu/sheetsu-ruby](https://github.com/sheetsu/sheetsu-ruby) 15 | * Node: [https://github.com/sheetsu/sheetsu-node](https://github.com/sheetsu/sheetsu-node) 16 | * JavaScript Web Client: [https://github.com/sheetsu/sheetsu-web-client](https://github.com/sheetsu/sheetsu-web-client) 17 | 18 | ### Community libraries 19 | 20 | * PHP: [https://github.com/emilianozublena/sheetsu-php](https://github.com/emilianozublena/sheetsu-php) 21 | * Python: [https://github.com/andreffs18/sheetsu-python](https://github.com/andreffs18/sheetsu-python) 22 | 23 | # How to prepare spreadsheet 24 | 25 | Every spreadsheet should have the first row populated with column names. There are no mandatory fields or values you _need_ to have in your spreadsheet. The structure of the spreadsheet is totally up to you. Just keep in mind, that the first row (row #1) is treated as there are column names. 26 | 27 | Column names can be anything. Strings, numbers, symbols, emojis 🙉 , anything. 28 | 29 | You can check example spreadsheet here. It looks like this: 30 | 31 | ![Example Spredsheet for Sheetsu.com](../images/example_spreadsheet.png) 32 | 33 | id | name | score 34 | ---|------|------ 35 | 1 | Peter | 42 36 | 2 | Lois | 89 37 | 3 | Meg | 10 38 | 4 | Chris | 42 39 | 5 | Stewie | 72 40 | 41 | # Google Spreadsheet URL 42 | 43 | To properly use Sheetsu, please paste Google Spreadsheets URL. Just copy the URL from the browser address bar. There's no need for sharing the Google Spreadsheet. 44 | 45 | ### Google Chrome 46 | ![Spreadsheet URL in Google Chrome](../images/chrome.png) 47 | 48 | ### Safari 49 | ![Spreadsheet URL in Safari](../images/safari.png) 50 | 51 | # About the API 52 | 53 | The Sheetsu API is meant to provide a RESTful way to interact with a Google Spreadsheets. Our API uses HTTP response codes to indicate API errors. We use built-in HTTP features, like HTTP Basic authentication and HTTP verbs, which are understood by off-the-shelf HTTP clients. 54 | 55 | We support cross-origin resource sharing. JSON is returned by all API responses, including errors, although our API libraries convert responses to appropriate language-specific objects. 56 | 57 | The requests in the right sidebar are designed to work as is. The sample requests are performed using our test API and test spreadsheet, which you can find [here](https://docs.google.com/spreadsheets/d/1WTwXrh2ZDXmXATZlQIuapdv4ldyhJGZg7LX8GlzPdZw/edit#gid=0). 58 | 59 | 63 | -------------------------------------------------------------------------------- /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 | @import url('https://fonts.googleapis.com/css?family=Roboto+Mono|Roboto:400,500,700'); 24 | 25 | // BACKGROUND COLORS 26 | //////////////////// 27 | // $nav-bg: #393939 !default; 28 | $nav-bg: #f8f8f8 !default; 29 | $examples-bg: #393939 !default; 30 | $code-bg: #292929 !default; 31 | $code-annotation-bg: #1c1c1c !default; 32 | $nav-subitem-bg: $nav-bg !default; 33 | $nav-active-bg: #3f88c5 !default; 34 | $lang-select-border: #000 !default; 35 | $lang-select-bg: #222 !default; 36 | $lang-select-active-bg: #118f57 !default; // feel free to change this to blue or something 37 | $lang-select-pressed-bg: #111 !default; // color of language tab bg when mouse is pressed 38 | $main-bg: #ffffff !default; 39 | $aside-notice-bg: #8fbcd4 !default; 40 | $aside-warning-bg: #c97a7e !default; 41 | $aside-success-bg: #6ac174 !default; 42 | $search-notice-bg: #c97a7e !default; 43 | 44 | 45 | // TEXT COLORS 46 | //////////////////// 47 | $main-text: #333 !default; // main content text color 48 | $nav-text: #333 !default; 49 | $nav-active-text: #fff !default; 50 | $lang-select-text: #fff !default; // color of unselected language tab text 51 | $lang-select-active-text: #fff !default; // color of selected language tab text 52 | $lang-select-pressed-text: #fff !default; // color of language tab text when mouse is pressed 53 | $border-color: #ddd !default; 54 | 55 | 56 | // SIZES 57 | //////////////////// 58 | $nav-width: 200px !default; // width of the navbar 59 | $examples-width: 50% !default; // portion of the screen taken up by code examples 60 | $logo-margin: 20px !default; // margin between nav items and logo, ignored if search is active 61 | $main-padding: 28px !default; // padding to left and right of content & examples 62 | $nav-padding: 15px !default; // padding to left and right of navbar 63 | $nav-v-padding: 10px !default; // padding used vertically around search boxes and results 64 | $nav-indent: 10px !default; // extra padding for ToC subitems 65 | $code-annotation-padding: 13px !default; // padding inside code annotations 66 | $h1-margin-bottom: 21px !default; // padding under the largest header tags 67 | $tablet-width: 930px !default; // min width before reverting to tablet size 68 | $phone-width: $tablet-width - $nav-width !default; // min width before reverting to mobile size 69 | 70 | 71 | // FONTS 72 | //////////////////// 73 | %default-font { 74 | font-family: 'Roboto', sans-serif; 75 | font-size: 16px; 76 | } 77 | 78 | %header-font { 79 | @extend %default-font; 80 | font-weight: bold; 81 | } 82 | 83 | %code-font { 84 | font-family: 'Roboto Mono', monospace; 85 | font-size: 14px; 86 | line-height: 1.5; 87 | } 88 | 89 | 90 | // OTHER 91 | //////////////////// 92 | $nav-active-shadow: #000 !default; 93 | $nav-footer-border-color: #ddd !default; 94 | $nav-embossed-border-top: #000 !default; 95 | $nav-embossed-border-bottom: #939393 !default; 96 | $main-embossed-text-shadow: 0px 1px 0px #fff !default; 97 | $search-box-border-color: #ddd !default; 98 | 99 | 100 | //////////////////////////////////////////////////////////////////////////////// 101 | // INTERNAL 102 | //////////////////////////////////////////////////////////////////////////////// 103 | // These settings are probably best left alone. 104 | 105 | %break-words { 106 | word-break: break-all; 107 | hyphens: auto; 108 | } 109 | -------------------------------------------------------------------------------- /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/includes/_other.md: -------------------------------------------------------------------------------- 1 | # Other 2 | Edit on GitHub 3 | 4 | # Multiple sheets 5 | ```shell 6 | # Get whole spreadsheet from sheet named Sheet2 7 | curl "https://sheetsu.com/apis/v1.0/020b2c0f/sheets/Sheet2" 8 | ``` 9 | 10 | ```shell 11 | # Adds single row to sheet named "Sheet2" 12 | curl "https://sheetsu.com/apis/v1.0/020b2c0f/sheets/Sheet2" \ 13 | -X POST \ 14 | -H "Content-Type: application/json" \ 15 | -d '{ "foo": "6", "another column": "quux" }' 16 | ``` 17 | 18 | ```ruby 19 | require 'sheetsu' 20 | sheetsu = Sheetsu::Client.new("020b2c0f") 21 | ``` 22 | 23 | ```ruby 24 | # Get whole spreadsheet from sheet named Sheet2 25 | sheetsu.read(sheet: "Sheet2") 26 | ``` 27 | 28 | ```ruby 29 | # Adds single row to sheet named "Sheet2" 30 | sheetsu.create({ "foo" => "bar", "another column" => "quux" }, "Sheet2") 31 | ``` 32 | 33 | By default, always the first sheet (aka worksheet aka tab) is accessed. To access other sheets within a spreadsheet add `/sheets/{sheet_name}` path to the URL if using cURL, or pass appropriate param when using a lib. 34 | 35 | # Authentication 36 | ```shell 37 | curl "https://sheetsu.com/apis/v1.0/020b2c0f" \ 38 | -u 'your_api_key:your_api_secret' 39 | ``` 40 | 41 | ```ruby 42 | # Create new client object with HTTP Basic Auth keys 43 | sheetsu = Sheetsu::Client.new( 44 | "020b2c0f", 45 | api_key: "YOUR_API_KEY", 46 | api_secret: "YOUR_API_SECRET" 47 | ) 48 | ``` 49 | 50 | You can secure your API with HTTP Basic authentication. It can be turned on in the API settings. 51 | 52 | You have to send `api_key` and `api_secret` when you have authentication turned on. 53 | 54 | # Creating API programmatically 55 | 56 | ```shell 57 | # Creates new API 58 | curl "https://sheetsu.com/apis/v1.0/api_sheets" \ 59 | -X POST \ 60 | -H "Content-Type: application/json" \ 61 | -d '{ "email": "your@email.com", "api_key": "api_key", "google_spreadsheet_url": "your_doc_url" }' 62 | ``` 63 | 64 | API can be created by sending `POST` request to `https://sheetsu.com/apis/v1.0/api_sheets`. This feature is not available in all plans - check [pricing page](https://sheetsu.com/pricing) to know more. 65 | Please contact 66 | support 67 | to get your `api_key`. 68 | 69 | ## Assigning permissions to an API 70 | While creating new API, you can assign read/write permission as well as set up authentication for the API. By default, all permissions are set to `true`. 71 | 72 | ```shell 73 | # Creates new API with HTTP Basic Auth 74 | curl "https://sheetsu.com/apis/v1.0/api_sheets" \ 75 | -X POST \ 76 | -H "Content-Type: application/json" \ 77 | -d '{ "email": "your@email.com", "api_key": "api_key", "google_spreadsheet_url": "your_doc_url", authenticate: true }' 78 | ``` 79 | 80 | ```shell 81 | # Creates new API with only write permission enabled 82 | curl "https://sheetsu.com/apis/v1.0/api_sheets" \ 83 | -X POST \ 84 | -H "Content-Type: application/json" \ 85 | -d '{ "email": "your@email.com", "api_key": "api_key", "google_spreadsheet_url": "your_doc_url", can_create: true, can_read: false, can_update: false, can_delete: false }' 86 | ``` 87 | 88 | # Rate Limits 89 | Every API has a rate limit. You can check rate limitś for APIs on the [pricing page](https://sheetsu.com/pricing). After hitting the limit for the particular API, you receive `429 Rate limit exceeded` status code. 90 | 91 | # HTTP Status Codes 92 | Every response from the API is a JSON encoded string with a significant HTTP status code. 93 | 94 | Code | Description 95 | -----|------------ 96 | `200 OK` | Standard response for successful GET, PUT and PATCH requests 97 | `201 Created` | Successful response for POST requests 98 | `204 No Content` | Successful response for DELETE requests 99 | `400 Bad Request` | Error response when creating (`POST`) or updating (`PUT`, `PATCH`) row(s) 100 | `401 Unauthorized` | Error response when wrong authorization credentials provided 101 | `402 Payment Required` | Returned if pro feature ([multiple sheets](#multiple-sheets)) is tried to be accessed from free account 102 | `403 Forbidden` | Error response when action is forbidden by the user (API owner) 103 | `404 No such route` | Error response when route doesn't exist 104 | `429 Rate limit exceeded` | Error response when API hits quota exceeded 105 | `500 Server error` | 106 | 107 | Each API URL has an `id`, which identifies it. It is part of the URL which is after `https://sheetsu.com/apis/v1.0/`. 108 | -------------------------------------------------------------------------------- /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/includes/_snippet.md: -------------------------------------------------------------------------------- 1 | # Snippet 2 | Edit on GitHub 3 | 4 | The snippet is our _"we are here for you"_ for all those, who don't want to play with any programming languages or development but want to have all the Sheetsu super powers on their websites. 5 | 6 | Snippet allows you to interact with a Google Spreadsheet from your website with just HTML. 7 | 8 | # Installation 9 | Add below code before closing `` tag. 10 | 11 | `` 12 | 13 | ### Hint 14 | If you are using Google Analytics, add it right after the Google Analytics script. 15 | 16 | # Read data from Spreadsheet 17 | ```html 18 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
    IdNameScore
    {{id}}{{name}}{{score}}
    37 | 38 | 39 | ``` 40 | 41 |
    42 |

    Above HTML will produce this result:

    43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
    IdNameScore
    1Peter42
    2Lois89
    3Meg10
    53 |
    54 | 55 | ```html 56 | 61 |
    62 | 63 |

    64 | Name: {{name}} 65 |
    66 | Email: {{email}} 67 |

    68 |
    69 | 70 | 71 | ``` 72 |
    73 |

    Above HTML will produce this result:

    74 |
    75 |
    76 |
    77 | 78 |

    79 | Name:Peter Griffin 80 |
    81 | Email:peter@griffin.com 82 |

    83 |
    84 |
    85 |
    86 | 87 |
    88 |

    89 | Name:Lois Griffin 90 |
    91 | Email:lois@griffin.com 92 |

    93 |
    94 |
    95 |
    96 |
    97 | 98 | 1. Add `sheetsu="YOUR_API_URL"` to the parent element. 99 | 2. Add handlebars ( `{{` and `}}` ) with column name to any child element, with column name. 100 | 101 | ### Search 102 | You can use an additional `sheetsu-search` attribute to show only results which are matching your search criteria. 103 | 104 | The value of the `sheetsu-search` attribute should be a key-value object ([JSON](http://json.org/example.html)) with column name and value you want to use for search. 105 | 106 | Remember to use single quote `'` around JSON and double quote `"` with JSON key, value names. 107 | 108 | ### Limit & offset 109 | 110 | Attributes you can use to manipulate results are `sheetsu-limit` and `sheetsu-offset`. 111 | 112 | *(We add a little bit of CSS styling to the results on the right)* 113 | 114 | # Save data to Spreadsheet 115 | ```html 116 | 121 |
    122 | 123 | 124 | 125 | 126 | 127 |
    128 | 129 | 130 | ``` 131 | 132 |
    133 |

    Above HTML will produce this result:

    134 |
    135 |
    136 | 137 | 138 |
    139 |
    140 | 141 |
    142 |
    143 | 144 |
    145 |
    146 |
    147 | 148 | 149 | 1. Add `sheetsu` attribute to the `
    ` element. 150 | 2. Add `` (or ` 41 | 42 | 43 |
    44 | 45 | 46 | ``` 47 | 48 | ```xml 49 | 54 |
    55 | 56 | 57 | 58 | 59 | 60 |
    61 | 62 | 63 | ``` 64 | 65 | ```ruby 66 | require 'sheetsu' 67 | sheetsu = Sheetsu::Client.new("https://sheetsu.com/apis/v1.0dr/020b2c0f") 68 | ``` 69 | 70 | ```ruby 71 | # Adds single row to spreadsheet 72 | sheetsu.create({ id: 7, name: "Glenn", score: "69" }) 73 | ``` 74 | 75 | ```ruby 76 | # Adds bunch of rows to spreadsheet 77 | rows = [ 78 | { id: 7, name: "Glenn", score: "69" }, 79 | { id: 8, name: "Brian", score: "77" }, 80 | { id: 9, name: "Joe", score: "45" } 81 | ] 82 | sheetsu.create(rows) 83 | ``` 84 | 85 | ```ruby 86 | # Adds single row to sheet named "Sheet2" 87 | sheetsu.create({ "foo" => "bar", "another column" => "quux" }, "Sheet2") 88 | ``` 89 | 90 | ```javascript--node 91 | var sheetsu = require('sheetsu-node') 92 | // import sheetsu from 'sheetsu-node' for ES6 93 | var client = sheetsu({ address: 'https://sheetsu.com/apis/v1.0dn/020b2c0f' }) 94 | ``` 95 | 96 | ```javascript--node 97 | // Adds single row to spreadsheet 98 | client.create({ id: 7, name: "Glenn", score: "69" }).then(function(data) { 99 | console.log(data); 100 | }, function(err){ 101 | console.log(err); 102 | }); 103 | ``` 104 | 105 | ```javascript--node 106 | // Adds bunch of rows to spreadsheet 107 | var rows = [ 108 | { id: 7, name: "Glenn", score: "69" }, 109 | { id: 8, name: "Brian", score: "77" }, 110 | { id: 9, name: "Joe", score: "45" } 111 | ] 112 | client.create(rows).then(function(data) { 113 | console.log(data); 114 | }, function(err){ 115 | console.log(err); 116 | }); 117 | ``` 118 | 119 | ```javascript--node 120 | // Adds single row to sheet named "Sheet2" 121 | client.create({ "foo": "bar", "another column": "quux" }, "Sheet2").then(function(data) { 122 | console.log(data); 123 | }, function(err){ 124 | console.log(err); 125 | }); 126 | ``` 127 | 128 | ```html--javascript 129 | 130 | 131 | 132 | 133 |
    134 | 135 | 136 | 137 |
    138 | 155 | 156 | ``` 157 | 158 | ```python 159 | from sheetsu import SheetsuClient 160 | client = SheetsuClient("https://sheetsu.com/apis/v1.0dy/020b2c0f") 161 | ``` 162 | 163 | ```python 164 | # Adds single row to spreadsheet 165 | client.create_one(id="7", name="Glenn", score="96") 166 | ``` 167 | 168 | ```python 169 | # Adds single row to spreadsheet to sheet named "Sheet2" 170 | client.create_one(sheet="Sheet2", foo="quux") 171 | ``` 172 | 173 | ```python 174 | # Adds bunch of rows to spreadsheet to sheet named "Sheet1" 175 | client.create_many( 176 | sheet="Sheet1", 177 | *[ 178 | dict(id="8", name="Brian", score="42"), 179 | dict(id="9", name="Joe", score="201") 180 | ] 181 | ) 182 | ``` 183 | 184 | ```php 185 | 'https://sheetsu.com/apis/v1.0dp/020b2c0f' 192 | ]); 193 | 194 | 195 | // Adds single row to spreadsheet 196 | $sheetsu->create([['id' => '7', 'name' => 'Glenn', 'score' => 96 ]]); 197 | 198 | 199 | // Adds single row to spreadsheet to sheet named "Sheet2" 200 | $sheetsu->sheet('Sheet2')->create([['id' => '8', 'name' => 'Glenn', 'score' => 96 ]]); 201 | 202 | 203 | // Adds bunch of rows to spreadsheet 204 | $sheetsu->create([ 205 | [ 'id' => '7', 'name' => 'Glenn', 'score' => '69' ], 206 | [ 'id' => '8', 'name' => 'Brian', 'score' => '77' ], 207 | [ 'id' => '9', 'name' => 'Joe', 'score' => '45' ] 208 | ]); 209 | 210 | ?> 211 | ``` 212 | 213 | ```javascript--jquery 214 | function successFunc(data) { 215 | console.log(data); 216 | } 217 | 218 | // Adds single row to spreadsheet 219 | var url = "https://sheetsu.com/apis/v1.0/020b2c0f"; 220 | var params = { id: 7, name: 'Glenn', score: 96 }; 221 | $.ajax({ type: "POST", url: url, data: params, success: successFunc }); 222 | 223 | 224 | // Adds single row to spreadsheet to sheet named "Sheet2" 225 | var url = "https://sheetsu.com/apis/v1.0dq/020b2c0f/sheets/Sheet2"; 226 | var params = { id: 7, name: 'Glenn', score: 96 }; 227 | $.ajax({ type: "POST", url: url, data: params, success: successFunc }); 228 | 229 | 230 | // Adds bunch of rows to spreadsheet 231 | var url = "https://sheetsu.com/apis/v1.0dq/020b2c0f"; 232 | var params = JSON.stringify({ 233 | rows: [ 234 | { id: 7, name: 'Glenn', score: 96 }, 235 | { id: 8, name: 'Brian', score: 77 }, 236 | { id: 9, name: 'Joe', score: 45 } 237 | ] 238 | }); 239 | $.ajax( 240 | { 241 | type: "POST", url: url, data: params, success: successFunc, 242 | contentType: 'application/json', processData: false 243 | } 244 | ); 245 | ``` 246 | 247 | ```csharp 248 | using System; 249 | using System.Net; 250 | using System.IO; 251 | 252 | namespace Sheetsu 253 | { 254 | public class Example 255 | { 256 | public static void Main(string[] args) 257 | { 258 | string apiUrl = @"https://sheetsu.com/apis/v1.0dc/020b2c0f"; 259 | string sheetsuResponse = string.Empty; 260 | 261 | HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(apiUrl); 262 | httpWebRequest.ContentType = "application/json"; 263 | httpWebRequest.Method = "POST"; 264 | 265 | StreamWriter streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()); 266 | string json = "{\"id\":\"6\", \"name\": \"Glenn\", \"score\": \"1000\"}"; 267 | 268 | streamWriter.Write(json); 269 | streamWriter.Flush(); 270 | streamWriter.Close(); 271 | 272 | HttpWebResponse response = (HttpWebResponse)httpWebRequest.GetResponse(); 273 | StreamReader reader = new StreamReader(response.GetResponseStream()); 274 | 275 | sheetsuResponse = reader.ReadToEnd(); 276 | } 277 | } 278 | } 279 | ``` 280 | 281 | ```swift 282 | import Foundation 283 | 284 | // Adds single row to spreadsheet 285 | let url = String(format: "https://sheetsu.com/apis/v1.0ds/020b2c0f") 286 | let serviceUrl = URL(string: url) 287 | let parameterDictionary = ["id" : "6", "name" : "Glenn", "score": "44"] 288 | var request = URLRequest(url: serviceUrl!) 289 | 290 | request.httpMethod = "POST" 291 | request.setValue("Application/json", forHTTPHeaderField: "Content-Type") 292 | 293 | let httpBody = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: []) 294 | 295 | request.httpBody = httpBody 296 | 297 | let session = URLSession.shared 298 | 299 | session.dataTask(with: request) { (data, response, error) in 300 | if let data = data { 301 | do { 302 | let json = try JSONSerialization.jsonObject(with: data, options: []) 303 | print(json) 304 | } catch { 305 | print(error) 306 | } 307 | } 308 | }.resume() 309 | ``` 310 | 311 | ```r 312 | library(httr) 313 | 314 | # Adds single row to spreadsheet 315 | body <- list(id = 7, name = "Glenn", score = 96) 316 | response <- POST("https://sheetsu.com/apis/v1.0dl/020b2c0f", body = body, encode = "json") 317 | data <- content(response, "parsed") 318 | 319 | # Adds single row to spreadsheet to sheet named "Sheet2" 320 | body <- list(id = 7, name = "Glenn", score = 96) 321 | response <- POST( 322 | "https://sheetsu.com/apis/v1.0dl/020b2c0f/sheets/Sheet2", 323 | body = body, 324 | encode = "json" 325 | ) 326 | data <- content(response, "parsed") 327 | 328 | # Adds bunch of rows to spreadsheet 329 | body <- list(rows = list( 330 | list(id = 7, name = "Glenn", score = 96), 331 | list(id = 7, name = "Glenn", score = 96), 332 | list(id = 7, name = "Glenn", score = 96)) 333 | ) 334 | response <- POST( 335 | "https://sheetsu.com/apis/v1.0dl/020b2c0f", 336 | body = body, 337 | encode = "json" 338 | ) 339 | data <- content(response, "parsed") 340 | ``` 341 | 342 | 343 | ```jsx 344 | // Display form, which will 345 | // save record to the Google Spreadsheet 346 | class SheetsuCreate extends React.Component { 347 | constructor(props) { 348 | super(props); 349 | this.state = { data: { id: '', name: '', score: '' } }; 350 | 351 | this.handleInputChange = this.handleInputChange.bind(this); 352 | this.handleSubmit = this.handleSubmit.bind(this); 353 | } 354 | 355 | handleInputChange(event) { 356 | var updatedData = this.state.data; 357 | updatedData[event.target.name] = event.target.value 358 | 359 | this.setState({ 360 | data: updatedData 361 | }); 362 | } 363 | 364 | handleSubmit(event) { 365 | event.preventDefault(); 366 | 367 | fetch("https://sheetsu.com/apis/v1.0dt/020b2c0f", { 368 | headers: { 369 | 'Accept': 'application/json', 370 | 'Content-Type': 'application/json' 371 | }, 372 | method: "POST", 373 | body: JSON.stringify(this.state.data) 374 | }).then( (response) => { 375 | return response.json() 376 | }).then( (json) => { 377 | console.log(json); 378 | }); 379 | } 380 | 381 | render() { 382 | return ( 383 |
    384 | 390 | 396 | 402 | 403 |
    404 | ); 405 | } 406 | } 407 | 408 | 409 | // Display form, which will 410 | // save record to the Google Spreadsheet 411 | // to sheet "Sheet1" 412 | class SheetsuCreate extends React.Component { 413 | constructor(props) { 414 | super(props); 415 | this.state = { data: { id: '', name: '', score: '' } }; 416 | 417 | this.handleInputChange = this.handleInputChange.bind(this); 418 | this.handleSubmit = this.handleSubmit.bind(this); 419 | } 420 | 421 | handleInputChange(event) { 422 | var updatedData = this.state.data; 423 | updatedData[event.target.name] = event.target.value 424 | 425 | this.setState({ 426 | data: updatedData 427 | }); 428 | } 429 | 430 | handleSubmit(event) { 431 | event.preventDefault(); 432 | 433 | fetch("https://sheetsu.com/apis/v1.0dt/020b2c0f/sheets/Sheet1", { 434 | headers: { 435 | 'Accept': 'application/json', 436 | 'Content-Type': 'application/json' 437 | }, 438 | method: "POST", 439 | body: JSON.stringify(this.state.data) 440 | }).then( (response) => { 441 | return response.json() 442 | }).then( (json) => { 443 | console.log(json); 444 | }); 445 | } 446 | 447 | render() { 448 | return ( 449 |
    450 | 456 | 462 | 468 | 469 |
    470 | ); 471 | } 472 | } 473 | ``` 474 | 475 | Add a row to Google Spreadsheet by sending a JSON object via `POST` request. 476 | 477 | ### Multiple rows 478 | Send an array of objects wrapped in `{ "rows": YOUR_ARRAY_HERE }` JSON to add multiple rows in one request. 479 | 480 | ### Returns 481 | An array of created objects. 482 | -------------------------------------------------------------------------------- /source/includes/core/_read.md: -------------------------------------------------------------------------------- 1 | # READ 2 | 3 | ## Read all data 4 | 5 | ```shell 6 | # Read whole spreadsheet 7 | curl "https://sheetsu.com/apis/v1.0db/020b2c0f" 8 | ``` 9 | 10 | ```shell 11 | # Read first two rows from sheet "Sheet2" 12 | curl "https://sheetsu.com/apis/v1.0db/020b2c0f/sheets/Sheet2?limit=2" 13 | ``` 14 | 15 | ```xml 16 | 17 |
    18 |

    Name: {{name}}

    19 |

    Score: {{score}}

    20 |
    21 | 22 | 23 | ``` 24 | 25 | ```xml 26 | 27 |
    28 |

    Name: {{name}}

    29 |

    Score: {{score}}

    30 |
    31 | 32 | 33 | ``` 34 | 35 | ```ruby 36 | require 'sheetsu' 37 | sheetsu = Sheetsu::Client.new("https://sheetsu.com/apis/v1.0dr/020b2c0f") 38 | ``` 39 | 40 | ```ruby 41 | # Read whole spreadsheet 42 | sheetsu.read 43 | ``` 44 | 45 | ```ruby 46 | # Read first two rows from sheet "Sheet2" 47 | sheetsu.read(sheet: "Sheet2", limit: 2) 48 | ``` 49 | 50 | ```javascript--node 51 | var sheetsu = require('sheetsu-node') 52 | // import sheetsu from 'sheetsu-node' for ES6 53 | var client = sheetsu({ address: 'https://sheetsu.com/apis/v1.0dn/020b2c0f' }) 54 | ``` 55 | 56 | ```javascript--node 57 | // Read whole spreadsheet 58 | client.read().then(function(data) { 59 | console.log(data); 60 | }, function(err){ 61 | console.log(err); 62 | }); 63 | ``` 64 | 65 | ```javascript--node 66 | // Read first two rows from sheet "Sheet2" 67 | client.read({ limit: 2, sheet: "Sheet2" }).then(function(data) { 68 | console.log(data); 69 | }, function(err){ 70 | console.log(err); 71 | }); 72 | ``` 73 | 74 | 75 | ```html--javascript 76 | 77 | 78 | 79 | 80 | 86 | 87 | ``` 88 | 89 | ```python 90 | from sheetsu import SheetsuClient 91 | client = SheetsuClient("https://sheetsu.com/apis/v1.0dy/020b2c0f") 92 | ``` 93 | 94 | ```python 95 | # Read first two rows from sheet "Sheet2" 96 | client.read(sheet="Sheet2", limit=2) 97 | ``` 98 | 99 | ```php 100 | 'https://sheetsu.com/apis/v1.0dp/020b2c0f' 107 | ]); 108 | 109 | 110 | // Read whole spreadsheet 111 | $response = $sheetsu->read(); 112 | $collection = $response->getCollection(); 113 | 114 | 115 | // Read first two rows from sheet "Sheet2" 116 | $response = $sheetsu->sheet('Sheet2')->read(2, 0); 117 | $collection = $response->getCollection(); 118 | 119 | ?> 120 | ``` 121 | 122 | ```javascript--jquery 123 | function successFunc(data) { 124 | console.log(data); 125 | } 126 | 127 | // Read whole spreadsheet 128 | var url = "https://sheetsu.com/apis/v1.0dq/020b2c0f"; 129 | $.ajax({ url: url, success: successFunc }); 130 | 131 | 132 | // Read first two rows from sheet "Sheet2" 133 | var url = "https://sheetsu.com/apis/v1.0dq/020b2c0f/sheets/Sheet2"; 134 | var params = { "limit": 2 }; 135 | $.ajax({ url: url, data: params, success: successFunc }); 136 | 137 | ``` 138 | 139 | ```csharp 140 | using System; 141 | using System.Net; 142 | using System.IO; 143 | 144 | namespace Sheetsu 145 | { 146 | public class Example 147 | { 148 | public static void Main(string[] args) 149 | { 150 | string sheetsuResponse = string.Empty; 151 | string apiUrl = @"https://sheetsu.com/apis/v1.0dc/020b2c0f"; 152 | 153 | HttpWebRequest request = (HttpWebRequest)WebRequest.Create(apiUrl); 154 | HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 155 | 156 | Stream stream = response.GetResponseStream(); 157 | StreamReader reader = new StreamReader(stream); 158 | sheetsuResponse = reader.ReadToEnd(); 159 | } 160 | } 161 | } 162 | ``` 163 | 164 | ```swift 165 | import Foundation 166 | 167 | // Read whole spreadsheet 168 | let url = String(format: "https://sheetsu.com/apis/v1.0ds/020b2c0f") 169 | let serviceUrl = URL(string: url) 170 | var request = URLRequest(url: serviceUrl!) 171 | 172 | request.httpMethod = "GET" 173 | request.setValue("Application/json", forHTTPHeaderField: "Content-Type") 174 | 175 | let session = URLSession.shared 176 | 177 | session.dataTask(with: request) { (data, response, error) in 178 | if let data = data { 179 | do { 180 | let json = try JSONSerialization.jsonObject(with: data, options: []) 181 | print(json) 182 | } catch { 183 | print(error) 184 | } 185 | } 186 | }.resume() 187 | ``` 188 | 189 | ```r 190 | library(httr) 191 | 192 | # Read whole spreadsheet 193 | response <- GET("https://sheetsu.com/apis/v1.0dl/020b2c0f") 194 | data <- content(response, "parsed") 195 | 196 | 197 | # Read first two rows from sheet "Sheet2" 198 | query = list(limit = 2) 199 | response <- GET( 200 | "https://sheetsu.com/apis/v1.0dl/020b2c0f/sheets/Sheet2", 201 | query = query 202 | ) 203 | data <- content(response, "parsed") 204 | ``` 205 | 206 | ```jsx 207 | // Read whole spreadsheet 208 | class SheetsuRead extends React.Component { 209 | constructor(props) { 210 | super(props); 211 | this.state = { 212 | data: [], 213 | }; 214 | } 215 | 216 | componentDidMount() { 217 | fetch("https://sheetsu.com/apis/v1.0dt/020b2c0f") 218 | .then( (response) => { 219 | return response.json() 220 | }).then( (json) => { 221 | this.setState({data: json}); 222 | }); 223 | } 224 | 225 | renderData() { 226 | return this.state.data.map((row) => 227 |
    {row.name} {row.score}
    228 | ); 229 | } 230 | 231 | render() { 232 | return ( 233 |
    234 | {this.renderData()} 235 |
    236 | ); 237 | } 238 | } 239 | 240 | 241 | // Read first two rows from sheet "Sheet1" 242 | class SheetsuRead extends React.Component { 243 | constructor(props) { 244 | super(props); 245 | this.state = { 246 | data: [], 247 | }; 248 | } 249 | 250 | componentDidMount() { 251 | fetch("https://sheetsu.com/apis/v1.0dt/020b2c0f/sheets/Sheet1?limit=2") 252 | .then( (response) => { 253 | return response.json() 254 | }).then( (json) => { 255 | this.setState({data: json}); 256 | }); 257 | } 258 | 259 | renderData() { 260 | return this.state.data.map((row) => 261 |
    {row.name} {row.score}
    262 | ); 263 | } 264 | 265 | render() { 266 | return ( 267 |
    268 | {this.renderData()} 269 |
    270 | ); 271 | } 272 | } 273 | 274 | ``` 275 | 276 | API can return whole Google Spreadsheet via a `GET` method to `https://sheetsu.com/apis/v1.0/{id}`. 277 | 278 | ### Request Parameters 279 | You can optionally limit results, or start with offset. 280 | 281 | Parameter | Description 282 | ----------|------------ 283 | limit | Number of how many rows should be returned 284 | offset | Number from which row response should start (default is 0) 285 | 286 | ### Returns 287 | An array of objects. Each object is a row from the Google Spreadsheet. 288 | 289 | ## Search spreadsheet 290 | ```shell 291 | # Get all rows where column 'score' is '42' 292 | curl "https://sheetsu.com/apis/v1.0db/020b2c0f/search?score=42" 293 | ``` 294 | 295 | ```shell 296 | # Get all rows where column 'score' is '42' 297 | # and column 'name' is 'Peter' 298 | curl "https://sheetsu.com/apis/v1.0db/020b2c0f/search?score=42&name=Peter" 299 | ``` 300 | 301 | ```shell 302 | # Get first two rows where column 'foo' is 'bar', 303 | # column 'another column' is '1' from sheet "Sheet2" 304 | curl "https://sheetsu.com/apis/v1.0db/020b2c0f/sheets/Sheet2/search?foo=bar&another%20column=1&limit=2" 305 | ``` 306 | 307 | ```shell 308 | # Get all rows where column 'name' is starting with 'p' 309 | curl "https://sheetsu.com/apis/v1.0db/020b2c0f/search?name=p*&ignore_case=true" 310 | ``` 311 | 312 | ```shell 313 | # Get all rows where column 'name' is contains string 'oi' 314 | curl "https://sheetsu.com/apis/v1.0db/020b2c0f/search?name=*oi*" 315 | ``` 316 | 317 | ```xml 318 | 319 |
    320 |

    Name: {{name}}, score: {{score}}

    321 |
    322 | 323 | 324 | ``` 325 | 326 | ```xml 327 | 331 |
    332 |

    Name: {{name}}, score: {{score}}

    333 |
    334 | 335 | 336 | ``` 337 | 338 | ```ruby 339 | require 'sheetsu' 340 | sheetsu = Sheetsu::Client.new("https://sheetsu.com/apis/v1.0dr/020b2c0f") 341 | ``` 342 | 343 | ```ruby 344 | # Get all rows where column 'score' is '42' 345 | sheetsu.read(search: { score: 42 }) 346 | ``` 347 | 348 | ```ruby 349 | # Get all rows where column 'score' is '42' 350 | # and column 'name' is 'Peter' 351 | sheetsu.read(search: { score: 42, name: "Peter" }) 352 | ``` 353 | 354 | ```ruby 355 | # Get first two rows where column 'foo' is 'bar', 356 | # column 'another column' is '1' from sheet "Sheet2" 357 | sheetsu.read( 358 | # search criteria 359 | search: { "foo" => "bar", "another column" => "1" }, 360 | limit: 2, # first two rows 361 | sheet: "Sheet2" # Sheet name 362 | ) 363 | ``` 364 | 365 | ```javascript--node 366 | var sheetsu = require('sheetsu-node') 367 | // import sheetsu from 'sheetsu-node' for ES6 368 | var client = sheetsu({ address: 'https://sheetsu.com/apis/v1.0dn/020b2c0f' }) 369 | ``` 370 | 371 | ```javascript--node 372 | // Get all rows where column 'score' is '42' 373 | client.read({ search: { score: 42 } }).then(function(data) { 374 | console.log(data); 375 | }, function(err){ 376 | console.log(err); 377 | }); 378 | ``` 379 | 380 | ```javascript--node 381 | // Get all rows where column 'score' is '42' 382 | // and column 'name' is 'Peter' 383 | client.read({ search: { score: 42, name: "Peter" } }).then(function(data) { 384 | console.log(data); 385 | }, function(err){ 386 | console.log(err); 387 | }); 388 | ``` 389 | 390 | ```javascript--node 391 | // Get first two rows where column 'foo' is 'bar', 392 | // column 'another column' is '1' from sheet "Sheet2" 393 | client.read({ 394 | limit: 2, // first two rows 395 | // search criteria 396 | search: { "foo": "bar", "another column": "1" }, 397 | sheet: "Sheet2" // Sheet name 398 | } 399 | ).then(function(data) { 400 | console.log(data); 401 | }, function(err){ 402 | console.log(err); 403 | }); 404 | ``` 405 | 406 | ```html--javascript 407 | 408 | 409 | 410 | 411 | 423 | 424 | ``` 425 | 426 | ```python 427 | from sheetsu import SheetsuClient 428 | client = SheetsuClient("https://sheetsu.com/apis/v1.0dy/020b2c0f") 429 | ``` 430 | 431 | ```python 432 | # Get all rows where column 'score' is '42' 433 | client.search(score="42") 434 | ``` 435 | 436 | ```python 437 | # Get all rows where column 'score' is '42' 438 | # and column 'name' is 'Peter' 439 | client.search(score="42", name="Peter") 440 | ``` 441 | 442 | ```python 443 | # Get first two rows where column 'foo' is 'bar' 444 | # from sheet "Sheet2" 445 | client.search(sheet="Sheet2", foo="bar", limit=2) 446 | ``` 447 | 448 | ```python 449 | # Get all rows where column 'name' is contains string 'oi' 450 | client.search(name="*oi*") 451 | ``` 452 | 453 | ```php 454 | 'https://sheetsu.com/apis/v1.0dp/020b2c0f' 461 | ]); 462 | 463 | 464 | // Get all rows where column 'score' is '42' 465 | $response = $sheetsu->search([ 466 | 'score' => '42' 467 | ]); 468 | $collection = $response->getCollection(); 469 | 470 | 471 | // Get all rows where column 'score' is '42' 472 | // and column 'name' is 'Peter' 473 | $response = $sheetsu->search([ 474 | 'name' => 'Peter', 475 | 'score' => '42' 476 | ]); 477 | $collection = $response->getCollection(); 478 | 479 | 480 | // Get first two rows where column 'foo' is 'bar' 481 | // from sheet "Sheet2" 482 | $response = $sheetsu->sheet('Sheet2')->search([ 483 | 'foo' => 'bar', 484 | ], 2, 0); 485 | $collection = $response->getCollection(); 486 | 487 | 488 | // Get all rows where column 'name' is contains string 'oi' 489 | $response = $sheetsu->search([ 490 | 'name' => '*oi*', 491 | ]); 492 | $collection = $response->getCollection(); 493 | 494 | ?> 495 | ``` 496 | 497 | ```javascript--jquery 498 | function successFunc(data) { 499 | console.log(data); 500 | } 501 | 502 | // Get all rows where column 'score' is '42' 503 | var url = "https://sheetsu.com/apis/v1.0dq/020b2c0f/search"; 504 | var params = { "score": 42 }; 505 | $.ajax({ url: url, data: params, success: successFunc }); 506 | 507 | 508 | // Get all rows where column 'score' is '42' 509 | // and column 'name' is 'Peter' 510 | var url = "https://sheetsu.com/apis/v1.0dq/020b2c0f/search"; 511 | var params = { "score": 42, "name": "Peter" }; 512 | $.ajax({ url: url, data: params, success: successFunc }); 513 | 514 | 515 | // Get first two rows where column 'foo' is 'bar' 516 | // from sheet "Sheet2" 517 | var url = "https://sheetsu.com/apis/v1.0dq/020b2c0f/sheets/Sheet2/search"; 518 | var params = { "foo": "bar" }; 519 | $.ajax({ url: url, data: params, success: successFunc }); 520 | 521 | 522 | // Get all rows where column 'name' contains string 'oi' 523 | var url = "https://sheetsu.com/apis/v1.0dq/020b2c0f/search"; 524 | var params = { "name": "*oi*" }; 525 | $.ajax({ url: url, data: params, success: successFunc }); 526 | ``` 527 | 528 | ```csharp 529 | using System; 530 | using System.Net; 531 | using System.IO; 532 | 533 | namespace Sheetsu 534 | { 535 | public class Example 536 | { 537 | public static void Main(string[] args) 538 | { 539 | string sheetsuResponse = string.Empty; 540 | string apiUrl = @"https://sheetsu.com/apis/v1.0dc/020b2c0f/search?score=42"; 541 | 542 | HttpWebRequest request = (HttpWebRequest)WebRequest.Create(apiUrl); 543 | HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 544 | 545 | Stream stream = response.GetResponseStream(); 546 | StreamReader reader = new StreamReader(stream); 547 | sheetsuResponse = reader.ReadToEnd(); 548 | } 549 | } 550 | } 551 | ``` 552 | 553 | ```swift 554 | import Foundation 555 | 556 | // Get all rows where column 'score' is '42' 557 | let url = String(format: "https://sheetsu.com/apis/v1.0ds/020b2c0f/search?score=42") 558 | let serviceUrl = URL(string: url) 559 | var request = URLRequest(url: serviceUrl!) 560 | request.httpMethod = "GET" 561 | request.setValue("Application/json", forHTTPHeaderField: "Content-Type") 562 | 563 | let session = URLSession.shared 564 | 565 | session.dataTask(with: request) { (data, response, error) in 566 | if let data = data { 567 | do { 568 | let json = try JSONSerialization.jsonObject(with: data, options: []) 569 | print(json) 570 | } catch { 571 | print(error) 572 | } 573 | } 574 | }.resume() 575 | ``` 576 | 577 | ```r 578 | library(httr) 579 | 580 | # Get all rows where column 'score' is '42' 581 | query <- list(score = 42) 582 | response <- GET( 583 | "https://sheetsu.com/apis/v1.0dl/020b2c0f/search", 584 | query = query 585 | ) 586 | data <- content(response, "parsed") 587 | 588 | 589 | # Get all rows where column 'score' is '42' 590 | # and column 'name' is 'Peter' 591 | query <- list(score = 42, name = "Peter") 592 | response <- GET( 593 | "https://sheetsu.com/apis/v1.0dl/020b2c0f/search", 594 | query = query 595 | ) 596 | data <- content(response, "parsed") 597 | 598 | 599 | # Get first two rows where column 'foo' is 'bar' 600 | # from sheet "Sheet2" 601 | query <- list(foo = "bar") 602 | response <- GET( 603 | "https://sheetsu.com/apis/v1.0dl/020b2c0f/sheets/Sheet2/search", 604 | query = query 605 | ) 606 | data <- content(response, "parsed") 607 | 608 | 609 | # Get all rows where column 'name' is contains string 'oi' 610 | query <- list(name = "*oi*") 611 | response <- GET( 612 | "https://sheetsu.com/apis/v1.0dl/020b2c0f/search", 613 | query = query 614 | ) 615 | data <- content(response, "parsed") 616 | ``` 617 | 618 | ```jsx 619 | // Get all records where score is 42 620 | class SheetsuSearch extends React.Component { 621 | constructor(props) { 622 | super(props); 623 | this.state = { 624 | data: [], 625 | }; 626 | } 627 | 628 | componentDidMount() { 629 | fetch("https://sheetsu.com/apis/v1.0dt/020b2c0f/search?score=42") 630 | .then( (response) => { 631 | return response.json() 632 | }).then( (json) => { 633 | this.setState({data: json}); 634 | }); 635 | } 636 | 637 | renderData() { 638 | return this.state.data.map((row) => 639 |
    {row.name} {row.score}
    640 | ); 641 | } 642 | 643 | render() { 644 | return ( 645 |
    646 | {this.renderData()} 647 |
    648 | ); 649 | } 650 | } 651 | 652 | 653 | // Get all records where score is 42 654 | // from sheet "Sheet1" 655 | class SheetsuSearch extends React.Component { 656 | constructor(props) { 657 | super(props); 658 | this.state = { 659 | data: [], 660 | }; 661 | } 662 | 663 | componentDidMount() { 664 | fetch("https://sheetsu.com/apis/v1.0dt/020b2c0f/sheets/Sheet1/search?score=42") 665 | .then( (response) => { 666 | return response.json() 667 | }).then( (json) => { 668 | this.setState({data: json}); 669 | }); 670 | } 671 | 672 | renderData() { 673 | return this.state.data.map((row) => 674 |
    {row.name} {row.score}
    675 | ); 676 | } 677 | 678 | render() { 679 | return ( 680 |
    681 | {this.renderData()} 682 |
    683 | ); 684 | } 685 | } 686 | ``` 687 | 688 | Search Google Spreadsheet for particular records. Pass params in a `column_name=value` as params to the `GET https://sheetsu.com/apis/v1.0/{id}/search` request. 689 | 690 | ### Wildcard searching 691 | You can search using wildcards (`*`). Asteriks (`*`) can represent any characters or empty string. 692 | 693 | ### Request Parameters 694 | You can optionally limit results, or start with offset. 695 | 696 | Parameter | Description 697 | ----------|------------ 698 | limit | Number of how many rows should be returned 699 | offset | Number from which row response should start (default is 0) 700 | ignore_case | Ignore letter case sensitivity. Both column names and values 701 | 702 | 703 | ### Returns 704 | An array of objects. Each object is a row from the Google Spreadsheet. 705 | -------------------------------------------------------------------------------- /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: normal; 72 | 73 | border-right: 1px solid $border-color; 74 | 75 | // language selector for mobile devices 76 | .lang-selector { 77 | display: none; 78 | a { 79 | padding-top: 0.5em; 80 | padding-bottom: 0.5em; 81 | } 82 | } 83 | 84 | // This is the logo at the top of the ToC 85 | &>img { 86 | display: block; 87 | max-width: 100%; 88 | } 89 | 90 | &>.search { 91 | position: relative; 92 | 93 | input { 94 | background: $nav-bg; 95 | border-width: 0 0 1px 0; 96 | border-color: $search-box-border-color; 97 | padding: 6px 0 6px 20px; 98 | box-sizing: border-box; 99 | margin: $nav-v-padding $nav-padding; 100 | width: $nav-width - 30; 101 | outline: none; 102 | color: $nav-text; 103 | border-radius: 0; /* ios has a default border radius */ 104 | } 105 | 106 | &:before { 107 | position: absolute; 108 | top: 17px; 109 | left: $nav-padding; 110 | color: $nav-text; 111 | @extend %icon-search; 112 | } 113 | } 114 | 115 | img+.tocify, .lang-selector+.tocify { 116 | margin-top: $logo-margin; 117 | } 118 | 119 | .search-results { 120 | margin-top: 0; 121 | box-sizing: border-box; 122 | height: 0; 123 | overflow-y: auto; 124 | overflow-x: hidden; 125 | transition-property: height, margin; 126 | transition-duration: 180ms; 127 | transition-timing-function: ease-in-out; 128 | &.visible { 129 | height: 30%; 130 | margin-bottom: 1em; 131 | border-top: 1px solid $border-color; 132 | border-bottom: 1px solid $border-color; 133 | } 134 | 135 | li { 136 | margin: 1em $nav-padding; 137 | line-height: 1; 138 | } 139 | 140 | a { 141 | color: $nav-text; 142 | text-decoration: none; 143 | 144 | &:hover { 145 | text-decoration: underline; 146 | } 147 | } 148 | } 149 | 150 | // Section headers 151 | .tocify-item[data-unique="introduction"], .tocify-item[data-unique="core"], .tocify-item[data-unique="other"], .tocify-item[data-unique="snippet"] { 152 | text-transform: uppercase; 153 | margin-top: 1em; 154 | font-weight: bold; 155 | cursor: default !important; 156 | } 157 | 158 | .tocify-focus[data-unique="introduction"], .tocify-focus[data-unique="core"], .tocify-focus[data-unique="other"], .tocify-focus[data-unique="snippet"] { 159 | background-color: transparent !important; 160 | box-shadow: none; 161 | color: $nav-text; 162 | } 163 | 164 | .tocify-item>a, .toc-footer li { 165 | padding: 0 $nav-padding 0 $nav-padding; 166 | display: block; 167 | overflow-x: hidden; 168 | white-space: nowrap; 169 | text-overflow: ellipsis; 170 | } 171 | 172 | // The Table of Contents is composed of multiple nested 173 | // unordered lists. These styles remove the default 174 | // styling of an unordered list because it is ugly. 175 | ul, li { 176 | list-style: none; 177 | margin: 0; 178 | padding: 0; 179 | line-height: 28px; 180 | } 181 | 182 | li { 183 | color: $nav-text; 184 | transition-property: background; 185 | transition-timing-function: linear; 186 | transition-duration: 230ms; 187 | } 188 | 189 | // This is the currently selected ToC entry 190 | .tocify-focus { 191 | background-color: $nav-active-bg; 192 | color: $nav-active-text; 193 | } 194 | 195 | // Subheaders are the submenus that slide open 196 | // in the table of contents. 197 | .tocify-subheader { 198 | display: none; // tocify will override this when needed 199 | background-color: $nav-subitem-bg; 200 | font-weight: normal; 201 | .tocify-item>a { 202 | padding-left: $nav-padding + $nav-indent; 203 | font-size: 12px; 204 | } 205 | 206 | // for embossed look: 207 | &>li:last-child { 208 | box-shadow: none; // otherwise it'll overflow out of the subheader 209 | } 210 | } 211 | 212 | .toc-footer { 213 | padding: 1em 0; 214 | margin-top: 1em; 215 | border-top: 1px dashed $nav-footer-border-color; 216 | 217 | li,a { 218 | color: $nav-text; 219 | text-decoration: none; 220 | } 221 | 222 | a:hover { 223 | text-decoration: underline; 224 | } 225 | 226 | li { 227 | font-size: 0.8em; 228 | line-height: 1.7; 229 | text-decoration: none; 230 | } 231 | } 232 | 233 | } 234 | 235 | // button to show navigation on mobile devices 236 | #nav-button { 237 | span { 238 | display: block; 239 | $side-pad: $main-padding / 2 - 8px; 240 | padding: $side-pad $side-pad $side-pad; 241 | background-color: rgba($main-bg, 0.7); 242 | transform-origin: 0 0; 243 | transform: rotate(-90deg) translate(-100%, 0); 244 | border-radius: 0 0 0 5px; 245 | } 246 | padding: 0 1.5em 5em 0; // increase touch size area 247 | display: none; 248 | position: fixed; 249 | top: 0; 250 | left: 0; 251 | z-index: 100; 252 | color: #000; 253 | text-decoration: none; 254 | font-weight: bold; 255 | opacity: 0.7; 256 | line-height: 16px; 257 | img { 258 | height: 16px; 259 | vertical-align: bottom; 260 | } 261 | 262 | transition: left 0.3s ease-in-out; 263 | 264 | &:hover { opacity: 1; } 265 | &.open {left: $nav-width} 266 | } 267 | 268 | 269 | //////////////////////////////////////////////////////////////////////////////// 270 | // PAGE LAYOUT AND CODE SAMPLE BACKGROUND 271 | //////////////////////////////////////////////////////////////////////////////// 272 | 273 | .page-wrapper { 274 | margin-left: $nav-width; 275 | position: relative; 276 | z-index: 10; 277 | background-color: $main-bg; 278 | min-height: 100%; 279 | 280 | padding-bottom: 1px; // prevent margin overflow 281 | 282 | // The dark box is what gives the code samples their dark background. 283 | // It sits essentially under the actual content block, which has a 284 | // transparent background. 285 | // I know, it's hackish, but it's the simplist way to make the left 286 | // half of the content always this background color. 287 | .dark-box { 288 | width: $examples-width; 289 | background-color: $examples-bg; 290 | position: absolute; 291 | right: 0; 292 | top: 0; 293 | bottom: 0; 294 | } 295 | 296 | .lang-selector { 297 | position: fixed; 298 | z-index: 50; 299 | padding: 10px 12px; 300 | } 301 | } 302 | 303 | .lang-selector { 304 | background-color: $lang-select-bg; 305 | font-weight: normal; 306 | a { 307 | display: block; 308 | float:left; 309 | color: $lang-select-text; 310 | text-decoration: none; 311 | padding: 0 16px; 312 | line-height: 32px; 313 | outline: 0; 314 | border-radius: 4px; 315 | margin: 0 8px; 316 | font-size: 14px; 317 | 318 | &:active, &:focus { 319 | background-color: $lang-select-pressed-bg; 320 | color: $lang-select-pressed-text; 321 | } 322 | 323 | &.active { 324 | background-color: $lang-select-active-bg; 325 | color: $lang-select-active-text; 326 | } 327 | } 328 | 329 | &:after { 330 | content: ''; 331 | clear: both; 332 | display: block; 333 | } 334 | } 335 | 336 | //////////////////////////////////////////////////////////////////////////////// 337 | // CONTENT STYLES 338 | //////////////////////////////////////////////////////////////////////////////// 339 | // This is all the stuff with the light background in the left half of the page 340 | 341 | .content { 342 | // to place content above the dark box 343 | position: relative; 344 | z-index: 30; 345 | 346 | &:after { 347 | content: ''; 348 | display: block; 349 | clear: both; 350 | } 351 | 352 | &>h1, &>h2, &>h3, &>h4, &>h5, &>h6, &>p, &>table, &>ul, &>ol, &>aside, &>dl { 353 | margin-right: $examples-width; 354 | padding: 0 $main-padding; 355 | box-sizing: border-box; 356 | display: block; 357 | text-shadow: $main-embossed-text-shadow; 358 | 359 | @extend %left-col; 360 | } 361 | 362 | &>ul, &>ol { 363 | padding-left: $main-padding + 15px; 364 | } 365 | 366 | // the div is the tocify hidden div for placeholding stuff 367 | &>h1, &>h2, &>div { 368 | clear:both; 369 | } 370 | 371 | h1 { 372 | @extend %header-font; 373 | font-size: 30px; 374 | padding-top: 0.5em; 375 | padding-bottom: 0.5em; 376 | margin-bottom: $h1-margin-bottom; 377 | margin-top: 2em; 378 | border-top: 1px solid $border-color; 379 | } 380 | 381 | h1:first-child, div:first-child + h1 { 382 | border-top-width: 0; 383 | margin-top: 0; 384 | } 385 | 386 | h2 { 387 | @extend %header-font; 388 | font-size: 20px; 389 | margin-top: 4em; 390 | margin-bottom: 0; 391 | border-top: 1px solid #ccc; 392 | padding-top: 1.2em; 393 | padding-bottom: 1.2em; 394 | background-image: linear-gradient(to bottom, rgba(#fff, 0.4), rgba(#fff, 0)); 395 | } 396 | 397 | // h2s right after h1s should bump right up 398 | // against the h1s. 399 | h1 + h2, h1 + div + h2 { 400 | margin-top: $h1-margin-bottom * -1; 401 | border-top: none; 402 | } 403 | 404 | h3, h4, h5, h6 { 405 | @extend %header-font; 406 | font-size: 15px; 407 | margin-top: 2.5em; 408 | margin-bottom: 0.8em; 409 | } 410 | 411 | h4, h5, h6 { 412 | font-size: 10px; 413 | } 414 | 415 | hr { 416 | margin: 2em 0; 417 | border-top: 2px solid $examples-bg; 418 | border-bottom: 2px solid $main-bg; 419 | } 420 | 421 | table { 422 | margin-bottom: 1em; 423 | overflow: auto; 424 | th,td { 425 | text-align: left; 426 | vertical-align: top; 427 | line-height: 1.6; 428 | } 429 | 430 | th { 431 | padding: 5px 10px; 432 | border-bottom: 1px solid #ccc; 433 | vertical-align: bottom; 434 | } 435 | 436 | td { 437 | padding: 10px; 438 | } 439 | 440 | tr:last-child { 441 | border-bottom: 1px solid #ccc; 442 | } 443 | 444 | tr:nth-child(odd)>td { 445 | background-color: lighten($main-bg,4.2%); 446 | } 447 | 448 | tr:nth-child(even)>td { 449 | background-color: lighten($main-bg,2.4%); 450 | } 451 | } 452 | 453 | dt { 454 | font-weight: bold; 455 | } 456 | 457 | dd { 458 | margin-left: 15px; 459 | } 460 | 461 | p, li, dt, dd { 462 | line-height: 1.6; 463 | margin-top: 0; 464 | } 465 | 466 | img { 467 | max-width: 100%; 468 | } 469 | 470 | code { 471 | background-color: rgba(0,0,0,0.05); 472 | padding: 3px; 473 | border-radius: 3px; 474 | @extend %break-words; 475 | @extend %code-font; 476 | } 477 | 478 | pre>code { 479 | background-color: transparent; 480 | padding: 0; 481 | } 482 | 483 | aside { 484 | padding-top: 1em; 485 | padding-bottom: 1em; 486 | text-shadow: 0 1px 0 lighten($aside-notice-bg, 15%); 487 | margin-top: 1.5em; 488 | margin-bottom: 1.5em; 489 | background: $aside-notice-bg; 490 | line-height: 1.6; 491 | 492 | &.warning { 493 | background-color: $aside-warning-bg; 494 | text-shadow: 0 1px 0 lighten($aside-warning-bg, 15%); 495 | } 496 | 497 | &.success { 498 | background-color: $aside-success-bg; 499 | text-shadow: 0 1px 0 lighten($aside-success-bg, 15%); 500 | } 501 | } 502 | 503 | aside:before { 504 | vertical-align: middle; 505 | padding-right: 0.5em; 506 | font-size: 14px; 507 | } 508 | 509 | aside.notice:before { 510 | @extend %icon-info-sign; 511 | } 512 | 513 | aside.warning:before { 514 | @extend %icon-exclamation-sign; 515 | } 516 | 517 | aside.success:before { 518 | @extend %icon-ok-sign; 519 | } 520 | 521 | .search-highlight { 522 | padding: 2px; 523 | margin: -2px; 524 | border-radius: 4px; 525 | border: 1px solid #F7E633; 526 | text-shadow: 1px 1px 0 #666; 527 | background: linear-gradient(to top left, #F7E633 0%, #F1D32F 100%); 528 | } 529 | } 530 | 531 | //////////////////////////////////////////////////////////////////////////////// 532 | // CODE SAMPLE STYLES 533 | //////////////////////////////////////////////////////////////////////////////// 534 | // This is all the stuff that appears in the right half of the page 535 | 536 | .content { 537 | pre, blockquote { 538 | background-color: $code-bg; 539 | color: #fff; 540 | 541 | padding: 2em $main-padding; 542 | margin: 0; 543 | width: $examples-width; 544 | 545 | float:right; 546 | clear:right; 547 | 548 | box-sizing: border-box; 549 | text-shadow: 0px 1px 2px rgba(0,0,0,0.4); 550 | 551 | @extend %right-col; 552 | 553 | &>p { margin: 0; } 554 | 555 | a { 556 | color: #fff; 557 | text-decoration: none; 558 | border-bottom: dashed 1px #ccc; 559 | } 560 | } 561 | 562 | pre { 563 | @extend %code-font; 564 | } 565 | 566 | blockquote { 567 | &>p { 568 | background-color: $code-annotation-bg; 569 | border-radius: 5px; 570 | padding: $code-annotation-padding; 571 | color: #ccc; 572 | border-top: 1px solid #000; 573 | border-bottom: 1px solid #404040; 574 | } 575 | } 576 | } 577 | 578 | //////////////////////////////////////////////////////////////////////////////// 579 | // RESPONSIVE DESIGN 580 | //////////////////////////////////////////////////////////////////////////////// 581 | // These are the styles for phones and tablets 582 | // There are also a couple styles disperesed 583 | 584 | @media (max-width: $tablet-width) { 585 | .tocify-wrapper { 586 | left: -$nav-width; 587 | 588 | &.open { 589 | left: 0; 590 | } 591 | } 592 | 593 | .page-wrapper { 594 | margin-left: 0; 595 | } 596 | 597 | #nav-button { 598 | display: block; 599 | } 600 | 601 | .tocify-wrapper .tocify-item > a { 602 | padding-top: 0.3em; 603 | padding-bottom: 0.3em; 604 | } 605 | } 606 | 607 | @media (max-width: $phone-width) { 608 | .dark-box { 609 | display: none; 610 | } 611 | 612 | %left-col { 613 | margin-right: 0; 614 | } 615 | 616 | .tocify-wrapper .lang-selector { 617 | display: block; 618 | } 619 | 620 | .page-wrapper .lang-selector { 621 | display: none; 622 | } 623 | 624 | %right-col { 625 | width: auto; 626 | float: none; 627 | } 628 | 629 | %right-col + %left-col { 630 | margin-top: $main-padding; 631 | } 632 | } 633 | 634 | .highlight .c, .highlight .cm, .highlight .c1, .highlight .cs { 635 | color: #909090; 636 | } 637 | 638 | .highlight, .highlight .w { 639 | background-color: $code-bg; 640 | } 641 | 642 | .gh-button { 643 | color: #000; 644 | text-decoration: none; 645 | font-size: 0.8em; 646 | font-weight: 700; 647 | padding: 0.3em 1.2em; 648 | border-radius: 1em; 649 | background-color: #e3e3e3; 650 | } 651 | 652 | .snippet-example { 653 | .character-card { 654 | border: 1px solid #E9E9E9; 655 | border-radius: 5px; 656 | padding: 10px; 657 | margin: 0 10px 10px 0; 658 | display: inline-block; 659 | 660 | img { 661 | width: 60px; 662 | } 663 | 664 | .char-details { 665 | display: inline-block; 666 | 667 | p { 668 | display: inline-block; 669 | margin: 0 0 0 10px; 670 | line-height: 24px; 671 | 672 | strong { 673 | margin-right: 8px; 674 | } 675 | } 676 | } 677 | } 678 | 679 | .column-50 { 680 | width: 60%; 681 | color: #000; 682 | margin-top: 1em; 683 | 684 | input { 685 | width: 100%; 686 | margin-bottom: 8px; 687 | padding: 6px 12px; 688 | border: 1px solid #ddd; 689 | border-radius: 5px; 690 | outline: none; 691 | } 692 | 693 | textarea { 694 | width: 100%; 695 | padding: 6px 12px; 696 | border: 1px solid #ddd; 697 | border-radius: 5px; 698 | outline: none; 699 | } 700 | } 701 | 702 | .button-wrapper { 703 | .button { 704 | background-color: #4487E9; 705 | border: 2px solid #4487E9; 706 | color: #fff; 707 | border-radius: 8px; 708 | padding: 6px 28px; 709 | font-weight: 400; 710 | } 711 | } 712 | } 713 | 714 | table.snippet-example-table { 715 | td { 716 | background-color: transparent !important; 717 | } 718 | } 719 | 720 | h1#introduction, h1#core, h1#snippet, h1#other { 721 | padding-bottom: 0.05em !important; 722 | margin-bottom: 0.05em !important; 723 | } 724 | 725 | .logo__holder { 726 | display: block; 727 | max-width: 100%; 728 | } 729 | .button__wrapper { 730 | margin: 20px 10px; 731 | } 732 | 733 | .button { 734 | display: inline-block; 735 | vertical-align: middle; 736 | cursor: pointer; 737 | white-space: nowrap; 738 | letter-spacing: 1.4px; 739 | text-align: center; 740 | text-shadow: none; 741 | text-transform: uppercase; 742 | overflow: hidden; 743 | text-decoration: none; 744 | position: relative; 745 | z-index: 2; 746 | width: 100%; 747 | line-height: 12px; 748 | padding: 15px 0; 749 | } 750 | 751 | .button--sign-up { 752 | background: rgb(88, 191, 131) !important; 753 | color: rgb(255, 255, 255); 754 | border-width: initial; 755 | border-style: none; 756 | border-color: initial; 757 | border-image: initial; 758 | border-radius: 3px; 759 | transition: all 0.4s ease; 760 | font: 700 12px "Open Sans", sans-serif; 761 | } 762 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------