Commit 525c13d8940ad0cb94ee66117553fe47ef6c4191

Authored by Luigi Serra
1 parent ac237fdd

google component tests

bower_components/google-sheets/.bower.json 0 → 100644
  1 +{
  2 + "name": "google-sheets",
  3 + "version": "1.0.5",
  4 + "homepage": "https://googlewebcomponents.github.io/google-sheets",
  5 + "description": "Web components to interact with Google Sheets",
  6 + "main": "google-sheets.html",
  7 + "authors": [
  8 + "Eric Bidelman <ebidel@gmail.com>"
  9 + ],
  10 + "license": "Apache2",
  11 + "ignore": [
  12 + "/.*",
  13 + "/test/"
  14 + ],
  15 + "keywords": [
  16 + "web-component",
  17 + "web-components",
  18 + "polymer",
  19 + "spreadsheets",
  20 + "google"
  21 + ],
  22 + "dependencies": {
  23 + "polymer": "Polymer/polymer#^1.1.2",
  24 + "google-apis": "GoogleWebComponents/google-apis#^1.1.0",
  25 + "google-signin": "GoogleWebComponents/google-signin#^1.0.3",
  26 + "iron-ajax": "PolymerElements/iron-ajax#^1.0.0"
  27 + },
  28 + "devDependencies": {
  29 + "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
  30 + "google-map": "GoogleWebComponents/google-map#^1.1.0",
  31 + "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
  32 + "web-component-tester": "*"
  33 + },
  34 + "_release": "1.0.5",
  35 + "_resolution": {
  36 + "type": "version",
  37 + "tag": "1.0.5",
  38 + "commit": "1e87081a4abfdd31cf7cbf4ac970c7f9873c447d"
  39 + },
  40 + "_source": "git://github.com/GoogleWebComponents/google-sheets.git",
  41 + "_target": "~1.0.5",
  42 + "_originalSource": "GoogleWebComponents/google-sheets",
  43 + "_direct": true
  44 +}
0 45 \ No newline at end of file
... ...
bower_components/google-sheets/LICENSE 0 → 100644
  1 +Copyright 2014 Google Inc
  2 +
  3 +Licensed under the Apache License, Version 2.0 (the "License");
  4 +you may not use this file except in compliance with the License.
  5 +You may obtain a copy of the License at
  6 +
  7 + https://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,
  11 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +See the License for the specific language governing permissions and
  13 +limitations under the License.
... ...
bower_components/google-sheets/README.md 0 → 100755
  1 +google-sheets
  2 +================
  3 +
  4 +See the [component page](https://googlewebcomponents.github.io/google-sheets) for more information.
... ...
bower_components/google-sheets/bower.json 0 → 100755
  1 +{
  2 + "name": "google-sheets",
  3 + "version": "1.0.5",
  4 + "homepage": "https://googlewebcomponents.github.io/google-sheets",
  5 + "description": "Web components to interact with Google Sheets",
  6 + "main": "google-sheets.html",
  7 + "authors": [
  8 + "Eric Bidelman <ebidel@gmail.com>"
  9 + ],
  10 + "license": "Apache2",
  11 + "ignore": [
  12 + "/.*",
  13 + "/test/"
  14 + ],
  15 + "keywords": [
  16 + "web-component",
  17 + "web-components",
  18 + "polymer",
  19 + "spreadsheets",
  20 + "google"
  21 + ],
  22 + "dependencies": {
  23 + "polymer": "Polymer/polymer#^1.1.2",
  24 + "google-apis": "GoogleWebComponents/google-apis#^1.1.0",
  25 + "google-signin": "GoogleWebComponents/google-signin#^1.0.3",
  26 + "iron-ajax": "PolymerElements/iron-ajax#^1.0.0"
  27 + },
  28 + "devDependencies": {
  29 + "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
  30 + "google-map": "GoogleWebComponents/google-map#^1.1.0",
  31 + "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
  32 + "web-component-tester": "*"
  33 + }
  34 +}
... ...
bower_components/google-sheets/demo/demo-private.html 0 → 100644
  1 +<!doctype html>
  2 +<!-- Copyright (c) 2015 Google Inc. All rights reserved. -->
  3 +<html>
  4 +<head>
  5 + <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
  6 + <title>google-sheets private data demo</title>
  7 + <script src="../../webcomponentsjs/webcomponents-lite.min.js"></script>
  8 + <link rel="import" href="../google-sheets.html">
  9 + <link rel="import" href="../../google-map/google-map.html">
  10 + <link rel="import" href="../../google-signin/google-signin.html">
  11 + <style>
  12 + * {
  13 + box-sizing: border-box;
  14 + }
  15 + body {
  16 + margin: 2em;
  17 + font-family: 'Roboto', 'Helvetica Neue', Helvetica, Arial;
  18 + font-weight: 300;
  19 + background-color: #f1f1f3;
  20 + }
  21 + a {
  22 + text-decoration: none;
  23 + color: blue;
  24 + }
  25 + ul {
  26 + padding-left: 0;
  27 + }
  28 + ul, li {
  29 + list-style: none;
  30 + font-size: 14px;
  31 + }
  32 + section {
  33 + border-radius: 3px;
  34 + box-shadow: 1px 1px 3px #ccc;
  35 + padding: 1em 2em;
  36 + background-color: white;
  37 + width: 500px;
  38 + min-height: 500px;
  39 + }
  40 + main {
  41 + justify-content: space-around;
  42 + margin-top: 2em;
  43 + }
  44 + </style>
  45 +</head>
  46 +<body>
  47 +
  48 +<google-signin
  49 + client-id="1054047045356-j8pgqgls9vdef3rl09hapoicumbte0bo.apps.googleusercontent.com"
  50 + scopes="https://spreadsheets.google.com/feeds">
  51 +</google-signin>
  52 +
  53 +<p>A <code>&lt;google-sheets></code> element returning data from a <b>private</b> Google Spreadsheet:</p>
  54 +<p><b>Note:</b> update the demo source to your clientId and private spreadsheet key for the demo to work.</p>
  55 +
  56 +<main class="layout horizontal">
  57 +
  58 +<template id="spreadsheets" is="dom-bind">
  59 +
  60 +<!-- Example: private spreadsheet -->
  61 +<google-sheets id="sheet" tab-id="1"
  62 + client-id="1054047045356-j8pgqgls9vdef3rl09hapoicumbte0bo.apps.googleusercontent.com"
  63 + key="1QMGizivw3UJ3-R9BFK7sfrXE0RL87dygk2C0RcuKoDY"
  64 + open-in-google-docs-url="{{openInGoogleDocsURL}}"
  65 + tab="{{tab}}"
  66 + spreadsheets="{{spreadsheets}}"
  67 + rows="{{rows}}"></google-sheets>
  68 +
  69 +<section>
  70 +
  71 + <heading>
  72 + <h3>List of spreadsheets</h3>
  73 + </heading>
  74 +
  75 + <ul>
  76 + <template is="dom-repeat" items="[[spreadsheets]]">
  77 + <li>{{item.title.$t}}</li>
  78 + </template>
  79 + </ul>
  80 +
  81 +</section>
  82 +
  83 +<section>
  84 +
  85 + <heading>
  86 + <h3>Spreadsheet rows:
  87 + <a href="{{openInGoogleDocsURL}}" target="_blank" title="Open in Google Docs &rarr;">
  88 + "<span>{{tab.title}}</span>" tab
  89 + </a>
  90 + </h3>
  91 + <h5>updated: <span>{{tab.updated}}</span>, by: <template is="dom-repeat" items="{{rows.authors}}"><span>{{item.name}}</span></template></h5>
  92 + </heading>
  93 + <ul>
  94 + <template is="dom-repeat" items="{{rows}}">
  95 + <li>Name: <span>{{item.gsx$name.$t}}</span> ( lat: <span>{{item.gsx$lat.$t}}</span>, lng: <span>{{item.gsx$lng.$t}}</span> )</li>
  96 + </template>
  97 + </ul>
  98 +
  99 +</section>
  100 +
  101 +</template>
  102 +
  103 +</main>
  104 +
  105 +</body>
  106 +</html>
... ...
bower_components/google-sheets/demo/index.html 0 → 100755
  1 +<!doctype html>
  2 +<!-- Copyright (c) 2015 Google Inc. All rights reserved. -->
  3 +<html>
  4 +<head>
  5 + <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
  6 + <title>google-sheets Demo</title>
  7 + <script src="../../webcomponentsjs/webcomponents-lite.min.js"></script>
  8 + <link rel="import" href="../../iron-flex-layout/classes/iron-flex-layout.html">
  9 + <link rel="import" href="../google-sheets.html">
  10 + <link rel="import" href="../../google-map/google-map.html">
  11 + <style>
  12 + * {
  13 + box-sizing: border-box;
  14 + }
  15 + body {
  16 + margin: 2em;
  17 + font-family: 'Roboto', 'Helvetica Neue', Helvetica, Arial;
  18 + font-weight: 300;
  19 + background-color: #f1f1f3;
  20 + }
  21 + a {
  22 + text-decoration: none;
  23 + color: blue;
  24 + }
  25 + ul {
  26 + padding-left: 0;
  27 + }
  28 + ul, li {
  29 + list-style: none;
  30 + font-size: 14px;
  31 + }
  32 + section {
  33 + border-radius: 3px;
  34 + box-shadow: 1px 1px 3px #ccc;
  35 + padding: 1em 2em;
  36 + background-color: white;
  37 + width: 500px;
  38 + height: 500px;
  39 + }
  40 + google-map {
  41 + display: block;
  42 + height: 100%;
  43 + width: 100%;
  44 + }
  45 + main {
  46 + justify-content: space-around;
  47 + margin-top: 2em;
  48 + }
  49 + </style>
  50 +</head>
  51 +<body>
  52 +
  53 +<p>A <code>&lt;google-sheets></code> element returns data from a Google Spreadsheet:</p>
  54 +
  55 +<main class="layout horizontal">
  56 +
  57 +<template id="container" is="dom-bind">
  58 +
  59 + <section>
  60 +
  61 + <!-- Example: published spreadsheet -->
  62 + <google-sheets id="sheet" key="0Anye-JMjUkZZdDBkMVluMEhZMmFGeHpYdDJJV1FBRWc" tab-id="1"
  63 + published rows="{{rows}}" tab="{{tab}}" open-in-google-docs-url="{{openInGoogleDocsUrl}}"></google-sheets>
  64 +
  65 + <heading>
  66 + <h3>Spreadsheet rows:
  67 + <a href="{{openInGoogleDocsUrl}}" target="_blank" title="Open in Google Docs &rarr;">
  68 + "<span>{{tab.title}}</span>" tab
  69 + </a>
  70 + </h3>
  71 + <h5>updated: <span>{{tab.updated}}</span>, by: <template is="dom-repeat" items="{{rows.authors}}">{{item.name}}</template></h5>
  72 + </heading>
  73 + <ul>
  74 + <template is="dom-repeat" items="[[rows]]">
  75 + <li>Name: <span>{{item.gsx$name.$t}}</span> ( lat: <span>{{item.gsx$lat.$t}}</span>, lng: <span>{{item.gsx$lng.$t}}</span> )</li>
  76 + </template>
  77 + </ul>
  78 +
  79 + </section>
  80 +
  81 + <section style="padding: 0;">
  82 +
  83 + <google-map disable-default-ui fit-to-markers>
  84 + <template is="dom-repeat" items="[[rows]]">
  85 + <google-map-marker latitude="{{item.gsx$lat.$t}}" longitude="{{item.gsx$lng.$t}}"></google-map-marker>
  86 + </template>
  87 + </google-map>
  88 +
  89 + <button on-click="useTab" data-tabid="1">View tab 1 data</button>
  90 + <button on-click="useTab" data-tabid="2">View tab 2 data</button>
  91 +
  92 + </section>
  93 +
  94 +</template>
  95 +</main>
  96 +
  97 +<script>
  98 +var template = document.querySelector('#container');
  99 +
  100 +template.useTab = function(e, detail, sender) {
  101 + document.querySelector('#sheet').tabId = Number(e.currentTarget.dataset.tabid);
  102 +};
  103 +</script>
  104 +</body>
  105 +</html>
... ...
bower_components/google-sheets/google-sheets.html 0 → 100755
  1 +<!-- Copyright (c) 2015 Google Inc. All rights reserved. -->
  2 +
  3 +<link rel="import" href="../polymer/polymer.html">
  4 +<link rel="import" href="../iron-ajax/iron-ajax.html">
  5 +<link rel="import" href="../google-signin/google-signin-aware.html">
  6 +
  7 +<!--
  8 +Element for interacting with Google Sheets.
  9 +
  10 +`<google-sheets>` pulls cell data from the Google Sheet specified by `key`.
  11 +A spreadsheet's key can be found in the URL when viewing it in google docs (e.g. `docs.google.com/spreadsheet/ccc?key=<KEY>#gid=12345`).
  12 +
  13 +Optionally, pass the `tab-id` attribute to specify a particular worksheet tab in the spreadsheet. For example, the first tab would be `tab-id="1"`. If `tab` is updated at a later time, the underlying data is also updated. **API calls are cached** as to not make extraneous calls.
  14 +
  15 +See [developers.google.com/google-apps/spreadsheets](https://developers.google.com/google-apps/spreadsheets) for full Spreadsheets API documentation.
  16 +
  17 +#### Example
  18 +
  19 + <google-sheets key="..." tab-id="1" client-id="..."></google-sheets>
  20 +
  21 + <script>
  22 + var sheet = document.querySelector('google-sheets');
  23 +
  24 + sheet.addEventListener('google-sheet-data', function(e) {
  25 + // this.spreadsheets - list of the user's spreadsheets
  26 + // this.tab - information on the tab that was fetched
  27 + // this.rows - cell row information for the tab that was fetched
  28 + });
  29 +
  30 + sheet.addEventListener('error', function(e) {
  31 + // e.detail.response
  32 + });
  33 + </script>
  34 +
  35 +<b>Example</b> - `published` is a perf optimization and hints that the spreadsheet has been published (public):
  36 +
  37 + <google-sheets key="0Anye-JMjUkZZdDBkMVluMEhZMmFGeHpYdDJJV1FBRWc" published></google-sheets>
  38 +
  39 +<b>Example</b> - leaving off the `key` returns as list of the user's spreadsheets.
  40 +
  41 + <google-sheets client-id="..."></google-sheets>
  42 +
  43 +<b>Example</b> - show a list of Map markers, using data-binding features inside Polymer:
  44 +
  45 + <template is="dom-bind">
  46 + <google-sheets
  47 + key="0Anye-JMjUkZZdDBkMVluMEhZMmFGeHpYdDJJV1FBRWc" tab-id="1" rows="{{rows}}"
  48 + client-id="...">
  49 + </google-sheets>
  50 + <google-map>
  51 + <google-map-marker latitude="{{gsx$lat.$t}}" longitude="{{gsx$lng.$t}}">
  52 + </google-map>
  53 + </template>
  54 +
  55 +<b>Example</b> - list a user's private spreadsheets. Authenticate with google-signin button.
  56 +
  57 + <google-signin
  58 + client-id="1054047045356-j8pgqgls9vdef3rl09hapoicumbte0bo.apps.googleusercontent.com"
  59 + scopes="https://spreadsheets.google.com/feeds">
  60 + </google-signin>
  61 +
  62 + <template is="dom-bind">
  63 + <google-sheets client-id="1054047045356-j8pgqgls9vdef3rl09hapoicumbte0bo.apps.googleusercontent.com"
  64 + key="1QMGizivw3UJ3-R9BFK7sfrXE0RL87dygk2C0RcuKoDY" tab-id="1"
  65 + spreadsheets="{{spreadsheets}}"></google-sheets>
  66 + <template is="dom-repeat" items="[[spreadsheets]]">
  67 + <p>{{item.title.$t}}</p>
  68 + </template>
  69 + </template>
  70 +
  71 +@demo
  72 +-->
  73 +
  74 +<dom-module id="google-sheets">
  75 + <template>
  76 + <template is="dom-if" if="{{!published}}">
  77 + <google-signin-aware client-id="{{clientId}}"
  78 + scopes="https://spreadsheets.google.com/feeds"
  79 + on-google-signin-aware-success="_onSignInSuccess"
  80 + on-google-signin-aware-signed-out="_onSignInFail"></google-signin-aware>
  81 + </template>
  82 +
  83 + <iron-ajax id="publicajax" params='{"alt": "json"}' handle-as="json"
  84 + on-response="_onCellRows"></iron-ajax>
  85 + <iron-ajax id="listsheetsajax" params='{"alt": "json"}' handle-as="json"
  86 + on-response="_onSpreadsheetList"></iron-ajax>
  87 + <iron-ajax id="worksheetajax" params='{"alt": "json"}' handle-as="json"
  88 + on-response="_onWorksheet"></iron-ajax>
  89 + <iron-ajax id="cellrowsajax" params='{"alt": "json"}' handle-as="json"
  90 + on-response="_onCellRows"></iron-ajax>
  91 +
  92 + </template>
  93 +</dom-module>
  94 +
  95 +<script>
  96 +(function() {
  97 + var SCOPE_ = 'https://spreadsheets.google.com/feeds';
  98 +
  99 + // Minimal cache for worksheet row data. Shared across instances so subsequent
  100 + // accesses are fast and API calls only happen once.
  101 + var rowDataCache_ = {};
  102 +
  103 + function generateCacheKey_() {
  104 + return this._worksheetId + '_'+ this.tabId;
  105 + }
  106 +
  107 + function getLink_(rel, links) {
  108 + for (var i = 0, link; link = links[i]; ++i) {
  109 + if (link.rel === rel) {
  110 + return link;
  111 + }
  112 + }
  113 + return null;
  114 + }
  115 +
  116 + // Conversion of Worksheet Ids to GIDs and vice versa
  117 + // od4 > 2
  118 + function wid_to_gid_(wid) {
  119 + return parseInt(String(wid), 36) ^ 31578;
  120 + }
  121 + // 2 > 0d4
  122 + function gid_to_wid_(gid) {
  123 + // (gid xor 31578) encoded in base 36
  124 + return parseInt((gid ^ 31578)).toString(36);
  125 + }
  126 +
  127 + window.GoogleSheets = Polymer({
  128 +
  129 + is: 'google-sheets',
  130 +
  131 + /**
  132 + * Fired when the spreadsheet's cell information is available.
  133 + *
  134 + * @event google-sheet-data
  135 + * @param {Object} detail
  136 + * @param {Object} detail.data The data returned by the Spreadsheet API.
  137 + * @param {string} detail.type The type of data that was fetched.
  138 + * One of 'spreadsheets', 'tab', 'rows' * to correspond to the feed type.
  139 + */
  140 +
  141 + hostAttributes: {
  142 + hidden: true
  143 + },
  144 +
  145 + properties: {
  146 + /**
  147 + * A Google Developers client ID. Obtain from [console.developers.google.com](https://console.developers.google.com). Required for accessing a private spreadsheet. Optional if accessing a public spreadsheet.
  148 + */
  149 + clientId: {
  150 + type: String,
  151 + value: '',
  152 + observer: '_configUpdate'
  153 + },
  154 +
  155 + /**
  156 + * The key of the spreadsheet. This can be found in the URL when viewing
  157 + * the document is Google Docs (e.g. `docs.google.com/spreadsheet/ccc?key=<KEY>`).
  158 + *
  159 + * Leaving off this attribute still returns a list of the users spreadsheets in the `spreadsheets` property.
  160 + */
  161 + key: {
  162 + type: String,
  163 + value: '',
  164 + observer: '_keyChanged'
  165 + },
  166 +
  167 + /**
  168 + * Tab within a spreadsheet. For example, the first tab in a spreadsheet
  169 + * would be `tab-id="1"`.
  170 + */
  171 + tabId: {
  172 + type: Number,
  173 + value: 1,
  174 + observer: '_configUpdate'
  175 + },
  176 +
  177 + /**
  178 + * A hint that the spreadsheet is published publicly in Google Docs. Used as a performance optimization.
  179 + * Make sure the sheet is also publicly viewable by anyone in the Share settings.
  180 + *
  181 + * @attribute published
  182 + * @type boolean
  183 + * @default false
  184 + */
  185 + published: {
  186 + type: Boolean,
  187 + value: false,
  188 + observer: '_configUpdate'
  189 + },
  190 +
  191 + /**
  192 + * The fetched sheet corresponding to the `key` attribute.
  193 + */
  194 + sheet: {
  195 + type: Object,
  196 + value: function() { return {}; },
  197 + readOnly: true,
  198 + notify: true,
  199 + observer: '_sheetChanged'
  200 + },
  201 +
  202 + /**
  203 + * Meta data about the particular tab that was retrieved for the spreadsheet.
  204 + */
  205 + tab: {
  206 + type: Object,
  207 + value: function() { return {}; },
  208 + readOnly: true,
  209 + notify: true,
  210 + observer: '_tabChanged'
  211 + },
  212 +
  213 + /**
  214 + * If a spreadsheet `key` is specified, returns a list of cell row data.
  215 + */
  216 + rows: {
  217 + type: Array,
  218 + value: function() { return []; },
  219 + readOnly: true,
  220 + notify: true
  221 + },
  222 +
  223 + /**
  224 + * List of the user's spreadsheets. Shared across instances.
  225 + */
  226 + spreadsheets: {
  227 + type: Array,
  228 + readOnly: true,
  229 + notify: true,
  230 + value: function() { return []; }
  231 + },
  232 +
  233 + /**
  234 + * The URL to open this spreadsheet in Google Sheets.
  235 + */
  236 + openInGoogleDocsUrl: {
  237 + type: String,
  238 + computed: '_computeGoogleDocsUrl(key)',
  239 + notify: true
  240 + }
  241 + },
  242 +
  243 + _worksheetId: null,
  244 +
  245 + _computeGoogleDocsUrl: function(key) {
  246 + var url = 'https://docs.google.com/spreadsheet/';
  247 + if (key) {
  248 + url += 'ccc?key=' + key;
  249 + }
  250 + return url;
  251 + },
  252 +
  253 + _configUpdate: function(key, published, tabId, clientId) {
  254 + this._tabIdChanged();
  255 + },
  256 +
  257 + _keyChanged: function(newValue, oldValue) {
  258 + // TODO(ericbidelman): need to better handle updates to the key attribute.
  259 + // Below doesn't account for private feeds.
  260 + if (this.published) {
  261 + var url = SCOPE_ + '/list/' + this.key + '/' +
  262 + this.tabId + '/public/values';
  263 + this.$.publicajax.url = url;
  264 + this.$.publicajax.generateRequest();
  265 + }
  266 + },
  267 +
  268 + _tabIdChanged: function(newValue, oldValue) {
  269 + if (this._worksheetId) {
  270 + this._getCellRows();
  271 + } else if (this.published) {
  272 + this._keyChanged();
  273 + }
  274 + },
  275 +
  276 + _sheetChanged: function(newValue, oldValue) {
  277 + if (!this.sheet.title) {
  278 + return;
  279 + }
  280 +
  281 + // Make metadata easily accessible on sheet object.
  282 + var authors = this.sheet.author && this.sheet.author.map(function(a) {
  283 + return {email: a.email.$t, name: a.name.$t};
  284 + });
  285 +
  286 + this.set('sheet.title', this.sheet.title.$t);
  287 + this.set('sheet.updated', new Date(this.sheet.updated.$t));
  288 + this.set('sheet.authors', authors);
  289 +
  290 + this._worksheetId = this.sheet.id.$t.split('/').slice(-1)[0];
  291 + this._getWorksheet();
  292 + },
  293 +
  294 + _tabChanged: function(newValue, oldValue) {
  295 + if (!this.tab.title) {
  296 + return;
  297 + }
  298 +
  299 + var authors = this.tab.authors = this.tab.author && this.tab.author.map(function(a) {
  300 + return {email: a.email.$t, name: a.name.$t};
  301 + });
  302 +
  303 + this.set('tab.title', this.tab.title.$t);
  304 + this.set('tab.updated', new Date(this.tab.updated.$t));
  305 + this.set('tab.authors', authors);
  306 +
  307 + this.fire('google-sheet-data', {
  308 + type: 'tab',
  309 + data: this.tab
  310 + });
  311 + },
  312 +
  313 + _onSignInSuccess: function(e, detail) {
  314 + var oauthToken = gapi.auth2.getAuthInstance().currentUser.get().getAuthResponse();
  315 +
  316 + var headers = {
  317 + 'Authorization': 'Bearer ' + oauthToken.access_token
  318 + };
  319 +
  320 + this.$.listsheetsajax.headers = headers;
  321 + this.$.worksheetajax.headers = headers;
  322 + this.$.cellrowsajax.headers = headers;
  323 +
  324 + // TODO(ericbidelman): don't make this call if this.spreadsheets is
  325 + // already populated from another instance.
  326 + this._listSpreadsheets();
  327 + },
  328 +
  329 + _onSignInFail: function(e, detail) {
  330 + // TODO(ericbidelman): handle this in some way.
  331 + console.log(e, e.type);
  332 + },
  333 +
  334 + _listSpreadsheets: function() {
  335 + var url = SCOPE_ + '/spreadsheets/private/full';
  336 + this.$.listsheetsajax.url = url;
  337 + this.$.listsheetsajax.generateRequest();
  338 + },
  339 +
  340 + _onSpreadsheetList: function(e) {
  341 + e.stopPropagation();
  342 +
  343 + var feed = e.target.lastResponse.feed;
  344 +
  345 + this._setSpreadsheets(feed.entry);
  346 +
  347 + this.fire('google-sheet-data', {
  348 + type: 'spreadsheets',
  349 + data: this.spreadsheets
  350 + });
  351 +
  352 + // Fetch worksheet feed if key was given and worksheet exists.
  353 + if (this.key) {
  354 + for (var i = 0, entry; entry = feed.entry[i]; ++i) {
  355 + var altLink = getLink_('alternate', entry.link);
  356 + if (altLink && altLink.href.indexOf(this.key) != -1) {
  357 + this._setSheet(entry);
  358 + break;
  359 + }
  360 + }
  361 + }
  362 + },
  363 +
  364 + _getWorksheet: function() {
  365 + if (!this._worksheetId) {
  366 + throw new Error('workesheetId was not given.');
  367 + }
  368 +
  369 + var url = SCOPE_ + '/worksheets/' + this._worksheetId +
  370 + '/private/full/' + this.tabId;
  371 + this.$.worksheetajax.url = url;
  372 + this.$.worksheetajax.generateRequest();
  373 + },
  374 +
  375 + _onWorksheet: function(e) {
  376 + e.stopPropagation();
  377 +
  378 + // this.tab = e.target.lastResponse.entry;
  379 + this._setTab(e.target.lastResponse.entry);
  380 + this._getCellRows();
  381 + },
  382 +
  383 + _getCellRows: function() {
  384 + // Use cached data if available.
  385 + var key = generateCacheKey_.call(this);
  386 + if (key in rowDataCache_) {
  387 + this._onCellRows(null, null, rowDataCache_[key]);
  388 +
  389 + return;
  390 + }
  391 +
  392 + var url = SCOPE_ + '/list/' +
  393 + this._worksheetId + '/' + this.tabId +
  394 + '/private/full';
  395 + this.$.cellrowsajax.url = url;
  396 + this.$.cellrowsajax.generateRequest();
  397 + },
  398 +
  399 + _onCellRows: function(e) {
  400 + e.stopPropagation();
  401 +
  402 + var feed = e.target.lastResponse.feed;
  403 +
  404 + // Cache data if key doesn't exist.
  405 + var key = generateCacheKey_.call(this);
  406 + if (!(key in rowDataCache_)) {
  407 + rowDataCache_[key] = {response: {feed: feed}};
  408 + }
  409 +
  410 + // this.rows = feed.entry;
  411 + this._setRows(feed.entry);
  412 + var authors = feed.author && feed.author.map(function(a) {
  413 + return {email: a.email.$t, name: a.name.$t};
  414 + });
  415 + this.set('rows.authors', authors);
  416 +
  417 + if (this.published) {
  418 + // this.tab = feed;
  419 + this._setTab(feed);
  420 + }
  421 +
  422 + this.fire('google-sheet-data', {
  423 + type: 'rows',
  424 + data: this.rows
  425 + });
  426 + }
  427 +
  428 + });
  429 +
  430 +})();
  431 +</script>
... ...
bower_components/google-sheets/index.html 0 → 100755
  1 +<!doctype html>
  2 +<!-- Copyright (c) 2015 Google Inc. All rights reserved. -->
  3 +<html>
  4 +<head>
  5 +
  6 + <script src="../webcomponentsjs/webcomponents-lite.js"></script>
  7 + <link rel="import" href="../iron-component-page/iron-component-page.html">
  8 +
  9 +</head>
  10 +<body>
  11 +
  12 + <iron-component-page></iron-component-page>
  13 +
  14 +</body>
  15 +</html>
... ...
bower_components/google-sheets/tests/google-sheet.html 0 → 100644
  1 +<!doctype html>
  2 +<!-- Copyright (c) 2015 Google Inc. All rights reserved. -->
  3 +<html>
  4 +<head>
  5 + <meta charset="utf-8">
  6 + <title>google-sheet tests</title>
  7 + <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
  8 +
  9 + <script src="../../../platform/platform.js"></script>
  10 + <link rel="import" href="../../../polymer-test-tools/tools.html">
  11 + <script src="../../../polymer-test-tools/htmltest.js"></script>
  12 +
  13 + <link rel="import" href="../google-sheets.html">
  14 +</head>
  15 +<body>
  16 +
  17 +<google-sheets id="sheet1"></google-sheets>
  18 +
  19 +<script>
  20 +document.addEventListener('polymer-ready', function() {
  21 +
  22 + (function() {
  23 + var sheet = document.querySelector('#sheet1');
  24 + var root = sheet.shadowRoot;
  25 +
  26 + // Check defaults.
  27 + assert.lengthOf(sheet.spreadsheets, 0,
  28 + '.spreadsheets length should default to 0');
  29 + assert.lengthOf(sheet.rows, 0, '.rows length should default to 0');
  30 + assert.isObject(sheet.sheet, '.sheet should default to {}');
  31 + assert.isObject(sheet.tab, '.tab should default to {}');
  32 +
  33 + assert.equal(sheet.key, '', ".key default is not ''");
  34 + assert.equal(sheet.gid, 0, '.gid default is not 0');
  35 + assert.isFalse(sheet.published, '.published does not default to false');
  36 + assert.isNotNull(root.querySelector('google-signin-aware'),
  37 + 'google-signin-aware should be created for non-public sheet');
  38 +
  39 + done();
  40 +
  41 + })();
  42 +
  43 +});
  44 +</script>
  45 +</body>
  46 +</html>
... ...
bower_components/google-sheets/tests/index.html 0 → 100644
  1 +<!doctype html>
  2 +<!-- Copyright (c) 2015 Google Inc. All rights reserved. -->
  3 +<html>
  4 + <head>
  5 + <meta charset="utf-8">
  6 + <title>Runs all tests</title>
  7 + <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
  8 + <script src="../../platform/platform.js"></script>
  9 + <link rel="import" href="tests.html">
  10 + </head>
  11 + <body>
  12 + <div id="mocha"></div>
  13 + </body>
  14 +</html>
... ...
bower_components/google-sheets/tests/private.html 0 → 100644
  1 +<!doctype html>
  2 +<!-- Copyright (c) 2015 Google Inc. All rights reserved. -->
  3 +<html>
  4 +<head>
  5 + <meta charset="utf-8">
  6 + <title>google-sheet tests</title>
  7 + <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
  8 +
  9 + <script src="../../../platform/platform.js"></script>
  10 + <link rel="import" href="../../../polymer-test-tools/tools.html">
  11 + <script src="../../../polymer-test-tools/htmltest.js"></script>
  12 +
  13 + <link rel="import" href="../google-sheets.html">
  14 +</head>
  15 +<body>
  16 +
  17 +<div>
  18 + <p>Tests live private spreadsheet data.</p>
  19 + <p>This test needs to be run manually, standalone in order to fetch an OAuth token.</p>
  20 +
  21 + <b>NOTES:</b><br>
  22 + <li>run manually off of localhost:3000/google-sheets/tests/private.html. Can also run from port 8080.</li>
  23 + <li>use the account: webcomponents.test@gmail.com</li>
  24 +</div>
  25 +
  26 +<google-sheets id="sheet" gid="1"
  27 + clientId="750497606405-1hq66meqmr4dp09dn54j9ggv85vbv0gp.apps.googleusercontent.com"
  28 + key="0AjqzxJ5RoRrWdGh2S0RRYURXTlNHdm9pQlFuM1ZwZWc"></google-sheets>
  29 +
  30 +<script>
  31 +document.addEventListener('polymer-ready', function() {
  32 +
  33 + (function() {
  34 + var sheet = document.querySelector('#sheet');
  35 + var root = sheet.shadowRoot;
  36 +
  37 + // Test set attributes.
  38 + assert.equal(sheet.key,
  39 + '0AjqzxJ5RoRrWdGh2S0RRYURXTlNHdm9pQlFuM1ZwZWc', ".key was not updated");
  40 + assert.equal(sheet.gid, 1, '.gid was not updated');
  41 + assert.equal(sheet.clientId,
  42 + '750497606405-1hq66meqmr4dp09dn54j9ggv85vbv0gp.apps.googleusercontent.com', ".clientId was not set");
  43 +
  44 + sheet.addEventListener('google-sheet-data', function(e) {
  45 +
  46 + switch (e.detail.type) {
  47 + case 'spreadsheets':
  48 + assert.isTrue(this.spreadsheets.length > 0,
  49 + '.spreadsheets should be populated for private feeds.');
  50 + break;
  51 + case 'tab':
  52 + assert.equal(this.tab.title, 'SECONDTAB', '.tab.title is incorrect');
  53 + break;
  54 + case 'rows':
  55 + assert.lengthOf(this.rows.authors, 1, '.rows.authors array');
  56 +
  57 + var name = this.rows.authors[0].name;
  58 + var email = this.rows.authors[0].email
  59 +
  60 + assert.equal(email, 'webcomponents.test@gmail.com', 'author email not set correctly');
  61 + assert.equal(name, 'webcomponents.test', 'author name not set correctly');
  62 +
  63 + assert.equal(this.rows[0].title.$t, 'FIRST NAME', '"name" column was incorrect');
  64 + assert.equal(this.rows[1].gsx$state.$t, 'OR', '"state" column was incorrect');
  65 +
  66 + break;
  67 + default:
  68 + // Noop
  69 + }
  70 +
  71 + done();
  72 +
  73 + });
  74 +
  75 + })();
  76 +
  77 +});
  78 +</script>
  79 +</body>
  80 +</html>
  81 +
... ...
bower_components/google-sheets/tests/published.html 0 → 100644
  1 +<!doctype html>
  2 +<!-- Copyright (c) 2015 Google Inc. All rights reserved. -->
  3 +<html>
  4 +<head>
  5 + <meta charset="utf-8">
  6 + <title>google-sheet tests</title>
  7 + <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
  8 +
  9 + <script src="../../../platform/platform.js"></script>
  10 + <link rel="import" href="../../../polymer-test-tools/tools.html">
  11 + <script src="../../../polymer-test-tools/htmltest.js"></script>
  12 +
  13 + <link rel="import" href="../google-sheets.html">
  14 +</head>
  15 +<body>
  16 +
  17 +<google-sheets id="sheet" key="0Anye-JMjUkZZdDBkMVluMEhZMmFGeHpYdDJJV1FBRWc"
  18 + published></google-sheets>
  19 +
  20 +<script>
  21 +document.addEventListener('polymer-ready', function() {
  22 +
  23 + var sheet = document.querySelector('#sheet');
  24 + var root = sheet.shadowRoot;
  25 +
  26 + assert.isTrue(sheet.published);
  27 + assert.isNull(root.querySelector('google-signin-aware'),
  28 + 'google-signin-aware should not be created for a published sheet');
  29 +
  30 + sheet.addEventListener('google-sheet-data', function(e) {
  31 +
  32 + if (e.detail.type === 'tab') {
  33 + assert.equal(this.tab.title, 'Locations',
  34 + 'Published spreadsheet title is not correct.');
  35 + assert.isNotNull(this.tab.updated, '.tab.updated was not set');
  36 + assert.isTrue(this.tab.authors.length > 0, '.tab.authors was 0');
  37 + } else if (e.detail.type === 'rows') {
  38 + assert.lengthOf(this.spreadsheets, 0,
  39 + '.spreadsheets length should be 0 since spreadsheet key was given');
  40 + assert.isTrue(this.rows.length > 0, '.rows was not populated');
  41 + }
  42 +
  43 + assert.equal(this.$.cellrowsajax.url, '',
  44 + '#cellrowsajax should not be invoked for a public spreadsheet');
  45 +
  46 + done();
  47 + });
  48 +});
  49 +</script>
  50 +</body>
  51 +</html>
... ...
bower_components/google-sheets/tests/tests.html 0 → 100644
  1 +<!-- Copyright (c) 2015 Google Inc. All rights reserved. -->
  2 +
  3 +<link rel="import" href="../../polymer-test-tools/tools.html">
  4 +<script src="../../polymer-test-tools/mocha-htmltest.js"></script>
  5 +
  6 +<script>
  7 +mocha.setup({ui: 'tdd', slow: 1000, timeout: 5000, htmlbase: ''});
  8 +
  9 +htmlSuite('google-sheet', function() {
  10 + htmlTest('google-sheet.html');
  11 + htmlTest('published.html');
  12 + htmlTest('private.html');
  13 +});
  14 +
  15 +mocha.run();
  16 +</script>
... ...
bower_components/google-signin/.bower.json 0 → 100644
  1 +{
  2 + "name": "google-signin",
  3 + "version": "1.2.0",
  4 + "description": "Web components to authenticate with Google services",
  5 + "homepage": "https://googlewebcomponents.github.io/google-signin",
  6 + "main": "google-signin.html",
  7 + "authors": [
  8 + "Addy Osmani",
  9 + "Randy Merrill"
  10 + ],
  11 + "license": "Apache-2",
  12 + "ignore": [
  13 + "/.*",
  14 + "/test/"
  15 + ],
  16 + "keywords": [
  17 + "web-component",
  18 + "web-components",
  19 + "polymer",
  20 + "sign-in",
  21 + "google",
  22 + "authentication"
  23 + ],
  24 + "dependencies": {
  25 + "polymer": "Polymer/polymer#^1.0.0",
  26 + "font-roboto": "PolymerElements/font-roboto#^1.0.0",
  27 + "iron-icon": "PolymerElements/iron-icon#^1.0.0",
  28 + "iron-icons": "PolymerElements/iron-icons#^1.0.0",
  29 + "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
  30 + "paper-ripple": "PolymerElements/paper-ripple#^1.0.0",
  31 + "paper-material": "PolymerElements/paper-material#^1.0.0",
  32 + "google-apis": "GoogleWebComponents/google-apis#^1.0.0"
  33 + },
  34 + "devDependencies": {
  35 + "iron-component-page": "PolymerElements/iron-component-page#^1.0.2"
  36 + },
  37 + "_release": "1.2.0",
  38 + "_resolution": {
  39 + "type": "version",
  40 + "tag": "v1.2.0",
  41 + "commit": "a1414b51b39e0a7dfe7031eb73a7733e2216579d"
  42 + },
  43 + "_source": "git://github.com/GoogleWebComponents/google-signin.git",
  44 + "_target": "^1.0.3",
  45 + "_originalSource": "GoogleWebComponents/google-signin"
  46 +}
0 47 \ No newline at end of file
... ...
bower_components/google-signin/LICENSE 0 → 100644
  1 +Copyright 2014 Google Inc
  2 +
  3 +Licensed under the Apache License, Version 2.0 (the "License");
  4 +you may not use this file except in compliance with the License.
  5 +You may obtain a copy of the License at
  6 +
  7 + https://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,
  11 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +See the License for the specific language governing permissions and
  13 +limitations under the License.
... ...
bower_components/google-signin/README.md 0 → 100644
  1 +google-signin
  2 +================
  3 +
  4 +See the [component page](https://googlewebcomponents.github.io/google-signin) for more information.
... ...
bower_components/google-signin/bower.json 0 → 100644
  1 +{
  2 + "name": "google-signin",
  3 + "version": "1.2.0",
  4 + "description": "Web components to authenticate with Google services",
  5 + "homepage": "https://googlewebcomponents.github.io/google-signin",
  6 + "main": "google-signin.html",
  7 + "authors": [
  8 + "Addy Osmani",
  9 + "Randy Merrill"
  10 + ],
  11 + "license": "Apache-2",
  12 + "ignore": [
  13 + "/.*",
  14 + "/test/"
  15 + ],
  16 + "keywords": [
  17 + "web-component",
  18 + "web-components",
  19 + "polymer",
  20 + "sign-in",
  21 + "google",
  22 + "authentication"
  23 + ],
  24 + "dependencies": {
  25 + "polymer": "Polymer/polymer#^1.0.0",
  26 + "font-roboto": "PolymerElements/font-roboto#^1.0.0",
  27 + "iron-icon": "PolymerElements/iron-icon#^1.0.0",
  28 + "iron-icons": "PolymerElements/iron-icons#^1.0.0",
  29 + "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
  30 + "paper-ripple": "PolymerElements/paper-ripple#^1.0.0",
  31 + "paper-material": "PolymerElements/paper-material#^1.0.0",
  32 + "google-apis": "GoogleWebComponents/google-apis#^1.0.0"
  33 + },
  34 + "devDependencies": {
  35 + "iron-component-page": "PolymerElements/iron-component-page#^1.0.2"
  36 + }
  37 +}
... ...
bower_components/google-signin/demo/index.html 0 → 100644
  1 +<!doctype html>
  2 +<!-- Copyright (c) 2014 Google Inc. All rights reserved. -->
  3 +<html>
  4 +<head>
  5 + <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
  6 +
  7 + <title>google-signin Demo</title>
  8 +
  9 + <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
  10 + <link rel="import" href="../google-signin.html">
  11 + <link rel="import" href="../google-signin-aware.html">
  12 +
  13 + <!-- Demo only styles -->
  14 + <style>
  15 + body {
  16 + font-family: 'RobotoDraft', 'Roboto', sans-serif;
  17 + line-height:1.2;
  18 + vertical-align:middle;
  19 + background: rgba(204, 204, 204, 0.31);
  20 + }
  21 +
  22 +
  23 + .map {
  24 + background: whitesmoke;
  25 + margin: .5rem -1.5rem 0 -1.5rem;
  26 + padding: 0.5rem;
  27 + }
  28 +
  29 + h1 {
  30 + font-size: 2rem;
  31 + font-weight:200;
  32 + clear: both;
  33 + }
  34 +
  35 + h1 strong {
  36 + font-weight:300;
  37 + color:#539D00;
  38 + }
  39 +
  40 + h2 {
  41 + font-size:.9rem;
  42 + line-height:2.5;
  43 + color:gray;
  44 + font-weight:400;
  45 + clear: both;
  46 + }
  47 +
  48 + .showcase {
  49 + display: inline-block;
  50 + margin-right: 2rem;
  51 + float: left;
  52 + }
  53 + </style>
  54 +
  55 +</head>
  56 +
  57 +<body>
  58 + <p>A <code>&lt;google-signin&gt;</code> element looks like this button:</p>
  59 +
  60 + <p><google-signin brand="google" client-id="1054047045356-j8pgqgls9vdef3rl09hapoicumbte0bo.apps.googleusercontent.com"></google-signin>
  61 +or like this if plus scopes are present
  62 + <google-signin brand="google-plus"></google-signin>
  63 + </p>
  64 + <p>Signin button can vary its appearance:</p>
  65 + <p>Width:
  66 + <google-signin brand="google" width="wide"></google-signin>
  67 + <google-signin brand="google" width="iconOnly"></google-signin>
  68 + Height:
  69 + <google-signin brand="google" height="tall"></google-signin>
  70 + <google-signin brand="google" height="standard"></google-signin>
  71 + <google-signin brand="google" height="short"></google-signin>
  72 + </p>
  73 + <p>
  74 + Theme:
  75 + <google-signin brand="google" theme="dark"></google-signin>
  76 + <google-signin brand="google" theme="light"></google-signin>
  77 + <google-signin brand="google-plus" theme="light"></google-signin>
  78 + <google-signin brand="google-plus" theme="light" raised></google-signin>
  79 + </p>
  80 + <!-- Demo the ability to use the google-signin-aware element. -->
  81 + <p><code>&lt;google-signin-aware&gt;</code> is a companion element.</p>
  82 + <p>You can use it inside your components to request additional scopes.</p>
  83 + <p>Every signin button will request all the scopes present in the document,
  84 + and change its appearance to match</p>
  85 + <p>For example, here is a signin-aware scope. You can change its scopes via popup</p>
  86 + <template id="awareness" is="dom-bind">
  87 + <div><code>&lt;google-signin-aware
  88 + <div>scope=
  89 + <select value="{{scope::change}}">
  90 + <option value="">None</option>
  91 + <option value="https://www.googleapis.com/auth/analytics">Google Analytics</option>
  92 + <option value="https://www.googleapis.com/auth/plus.login">Google Plus view circles</option>
  93 + <option value="https://www.googleapis.com/auth/youtube">YouTube</option>
  94 + <option value="https://www.googleapis.com/auth/calendar">Calendar</option>
  95 + <option value="profile">Profile info</option>
  96 + </select>
  97 + </div>
  98 + <div>offline=<input type="checkbox" checked="{{offline::change}}"></div>
  99 + <div>signedIn="<span>{{signedIn}}</span>"</div>
  100 + <div>isAuthorized="<span>{{isAuthorized}}</span>"</div>
  101 + <div>needAdditionalAuth:"<span>{{needAdditionalAuth}}</span>"&gt;</div>
  102 + </code></div>
  103 + <p>Every new scope you select will be added to requested scopes.</p>
  104 + <p>When you select a Google Plus scope, button will turn red.</p>
  105 + <google-signin></google-signin>
  106 + </p>
  107 + <google-signin-aware
  108 + scopes="{{scope}}"
  109 + signed-in="{{signedIn}}"
  110 + offline="{{offline}}"
  111 + is-authorized="{{isAuthorized}}"
  112 + need-additional-auth="{{needAdditionalAuth}}"
  113 + on-google-signin-aware-success="handleSignIn"
  114 + on-google-signin-offline-success="handleOffline"
  115 + on-google-signin-aware-signed-out="handleSignOut"></google-signin-aware>
  116 + <p>User name:<span>{{userName}}</span></p>
  117 + <p>Testing <code>google-signin-aware</code> events: <span>{{status}}</span></p>
  118 + <p>Testing <code>google-signin-offline</code> events: <span>{{offlineCode}}</span></p>
  119 + <p><button on-click="disconnect">Disconnect to start over</button></p>
  120 + </template>
  121 + <script>
  122 + var aware = document.querySelector('#awareness');
  123 + aware.status = 'Not granted';
  124 + aware.offlineCode = 'No offline login.';
  125 + aware.userName = 'N/A';
  126 + aware.handleSignIn = function(response) {
  127 + this.status = 'Signin granted';
  128 + // console.log('[Aware] Signin Response', response);
  129 + this.userName = gapi.auth2.getAuthInstance().currentUser.get().getBasicProfile().getName();
  130 + };
  131 + aware.handleOffline = function(response) {
  132 + this.offlineCode = response.detail.code;
  133 + };
  134 + aware.handleSignOut = function(response) {
  135 + this.status = 'Signed out';
  136 + // console.log('[Aware] Signout Response', response);
  137 + this.userName = 'N/A';
  138 + };
  139 + aware.disconnect = function() {
  140 + var b = document.querySelector('google-signin');
  141 + var currentUser = gapi.auth2.getAuthInstance().currentUser.get();
  142 + if (currentUser) {
  143 + currentUser.disconnect();
  144 + }
  145 + gapi.auth2.getAuthInstance().signOut();
  146 + };
  147 +
  148 + </script>
  149 +</body>
  150 +</html>
... ...
bower_components/google-signin/google-icons.html 0 → 100644
  1 +<!--
  2 +Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
  3 +This code may only be used under the BSD style license found at https://polymer.github.io/LICENSE.txt
  4 +The complete set of authors may be found at https://polymer.github.io/AUTHORS.txt
  5 +The complete set of contributors may be found at https://polymer.github.io/CONTRIBUTORS.txt
  6 +Code distributed by Google as part of the polymer project is also
  7 +subject to an additional IP rights grant found at https://polymer.github.io/PATENTS.txt
  8 +-->
  9 +
  10 +<link rel="import" href="../iron-icon/iron-icon.html">
  11 +<link rel="import" href="../iron-iconset-svg/iron-iconset-svg.html">
  12 +<iron-iconset-svg name="google" iconSize="24">
  13 +<svg><defs>
  14 +<g id="google"><path d="M16.3,13.4l-1.1-0.8c-0.4-0.3-0.8-0.7-0.8-1.4c0-0.7,0.5-1.3,1-1.6c1.3-1,2.6-2.1,2.6-4.3c0-2.1-1.3-3.3-2-3.9h1.7L18.9,0h-6.2C8.3,0,6.1,2.8,6.1,5.8c0,2.3,1.8,4.8,5,4.8h0.8c-0.1,0.3-0.4,0.8-0.4,1.3c0,1,0.4,1.4,0.9,2c-1.4,0.1-4,0.4-5.9,1.6c-1.8,1.1-2.3,2.6-2.3,3.7c0,2.3,2.1,4.5,6.6,4.5c5.4,0,8-3,8-5.9C18.8,15.7,17.7,14.6,16.3,13.4z M8.7,4.3c0-2.2,1.3-3.2,2.7-3.2c2.6,0,4,3.5,4,5.5c0,2.6-2.1,3.1-2.9,3.1C10,9.7,8.7,6.6,8.7,4.3z M12.3,22.3c-3.3,0-5.4-1.5-5.4-3.7c0-2.2,2-2.9,2.6-3.2c1.3-0.4,3-0.5,3.3-0.5c0.3,0,0.5,0,0.7,0c2.4,1.7,3.4,2.4,3.4,4C16.9,20.8,15,22.3,12.3,22.3z"/></g>
  15 +<g id="google-plus"><path d="M21,10V7h-2v3h-3v2h3v3h2v-3h3v-2H21z M13.3,13.4l-1.1-0.8c-0.4-0.3-0.8-0.7-0.8-1.4c0-0.7,0.5-1.3,1-1.6c1.3-1,2.6-2.1,2.6-4.3c0-2.1-1.3-3.3-2-3.9h1.7L15.9,0H9.7C5.3,0,3.1,2.8,3.1,5.8c0,2.3,1.8,4.8,5,4.8h0.8c-0.1,0.3-0.4,0.8-0.4,1.3c0,1,0.4,1.4,0.9,2c-1.4,0.1-4,0.4-5.9,1.6c-1.8,1.1-2.3,2.6-2.3,3.7c0,2.3,2.1,4.5,6.6,4.5c5.4,0,8-3,8-5.9C15.8,15.7,14.7,14.6,13.3,13.4z M5.7,4.3c0-2.2,1.3-3.2,2.7-3.2c2.6,0,4,3.5,4,5.5c0,2.6-2.1,3.1-2.9,3.1C7,9.7,5.7,6.6,5.7,4.3z M9.3,22.3c-3.3,0-5.4-1.5-5.4-3.7c0-2.2,2-2.9,2.6-3.2c1.3-0.4,3-0.5,3.3-0.5c0.3,0,0.5,0,0.7,0c2.4,1.7,3.4,2.4,3.4,4C13.9,20.8,12,22.3,9.3,22.3z"/></g>
  16 +</defs></svg>
  17 +</iron-iconset-svg>
... ...
bower_components/google-signin/google-signin-aware.html 0 → 100644
  1 +<link rel="import" href="../polymer/polymer.html">
  2 +<link rel="import" href="../google-apis/google-js-api.html">
  3 +
  4 +<script>
  5 + (function() {
  6 +
  7 + /**
  8 + * Enum of attributes to be passed through to the login API call.
  9 + * @readonly
  10 + * @enum {string}
  11 + */
  12 + var ProxyLoginAttributes = {
  13 + 'appPackageName': 'apppackagename',
  14 + 'clientId': 'clientid',
  15 + 'cookiePolicy': 'cookiepolicy',
  16 + 'requestVisibleActions': 'requestvisibleactions',
  17 + 'hostedDomain': 'hostedDomain'
  18 + };
  19 +
  20 + /**
  21 + * AuthEngine does all interactions with gapi.auth2
  22 + *
  23 + * It is tightly coupled with <google-signin-aware> element
  24 + * The elements configure AuthEngine.
  25 + * AuthEngine propagates all authentication events to all google-signin-aware elements
  26 + *
  27 + * API used: https://developers.google.com/identity/sign-in/web/reference
  28 + *
  29 + */
  30 + var AuthEngine = {
  31 +
  32 + /**
  33 + * oauth2 argument, set by google-signin-aware
  34 + */
  35 + _clientId: null,
  36 +
  37 + get clientId() {
  38 + return this._clientId;
  39 + },
  40 +
  41 + set clientId(val) {
  42 + if (this._clientId && val && val != this._clientId) {
  43 + throw new Error('clientId cannot change. Values do not match. New: ' + val + ' Old:' + this._clientId);
  44 + }
  45 + if (val) {
  46 + this._clientId = val;
  47 + this.initAuth2();
  48 + }
  49 + },
  50 +
  51 + /**
  52 + * oauth2 argument, set by google-signin-aware
  53 + */
  54 + _cookiePolicy: 'single_host_origin',
  55 +
  56 + get cookiePolicy() {
  57 + return this._cookiePolicy;
  58 + },
  59 +
  60 + set cookiePolicy(val) {
  61 + if (val) {
  62 + this._cookiePolicy = val;
  63 + }
  64 + },
  65 +
  66 + /**
  67 + * oauth2 argument, set by google-signin-aware
  68 + */
  69 + _appPackageName: '',
  70 +
  71 + get appPackageName() {
  72 + return this._appPackageName;
  73 + },
  74 +
  75 + set appPackageName(val) {
  76 + if (this._appPackageName && val && val != this._appPackageName) {
  77 + throw new Error('appPackageName cannot change. Values do not match. New: ' + val + ' Old: ' + this._appPackageName);
  78 + }
  79 + if (val) {
  80 + this._appPackageName = val;
  81 + }
  82 + },
  83 +
  84 + /**
  85 + * oauth2 argument, set by google-signin-aware
  86 + */
  87 + _requestVisibleActions: '',
  88 +
  89 + get requestVisibleactions() {
  90 + return this._requestVisibleActions;
  91 + },
  92 +
  93 + set requestVisibleactions(val) {
  94 + if (this._requestVisibleActions && val && val != this._requestVisibleActions) {
  95 + throw new Error('requestVisibleactions cannot change. Values do not match. New: ' + val + ' Old: ' + this._requestVisibleActions);
  96 + }
  97 + if (val)
  98 + this._requestVisibleActions = val;
  99 + },
  100 +
  101 + /**
  102 + * oauth2 argument, set by google-signin-aware
  103 + */
  104 + _hostedDomain: '',
  105 +
  106 + get hostedDomain() {
  107 + return this._hostedDomain;
  108 + },
  109 +
  110 + set hostedDomain(val) {
  111 + if (this._hostedDomain && val && val != this._hostedDomain) {
  112 + throw new Error('hostedDomain cannot change. Values do not match. New: ' + val + ' Old: ' + this._hostedDomain);
  113 + }
  114 + if (val)
  115 + this._hostedDomain = val;
  116 + },
  117 +
  118 + /** Is offline access currently enabled in the google-signin-aware element? */
  119 + _offline: false,
  120 +
  121 + get offline() {
  122 + return this._offline;
  123 + },
  124 +
  125 + set offline(val) {
  126 + this._offline = val;
  127 + this.updateAdditionalAuth();
  128 + },
  129 +
  130 + /** Should we force a re-prompt for offline access? */
  131 + _offlineAlwaysPrompt: false,
  132 +
  133 + get offlineAlwaysPrompt() {
  134 + return this._offlineAlwaysPrompt;
  135 + },
  136 +
  137 + set offlineAlwaysPrompt(val) {
  138 + this._offlineAlwaysPrompt = val;
  139 + this.updateAdditionalAuth();
  140 + },
  141 +
  142 + /** Have we already gotten offline access from Google during this session? */
  143 + offlineGranted: false,
  144 +
  145 + /** <google-js-api> */
  146 + _apiLoader: null,
  147 +
  148 + /** an array of wanted scopes. oauth2 argument */
  149 + _requestedScopeArray: [],
  150 +
  151 + /** _requestedScopeArray as string */
  152 + get requestedScopes() {
  153 + return this._requestedScopeArray.join(' ');
  154 + },
  155 +
  156 + /** Is user signed in? */
  157 + _signedIn: false,
  158 +
  159 + /** Currently granted scopes */
  160 + _grantedScopeArray: [],
  161 +
  162 + /** True if additional authorization is required */
  163 + _needAdditionalAuth: true,
  164 +
  165 + /** True if have google+ scopes */
  166 + _hasPlusScopes: false,
  167 +
  168 + /**
  169 + * array of <google-signin-aware>
  170 + * state changes are broadcast to them
  171 + */
  172 + signinAwares: [],
  173 +
  174 + init: function() {
  175 + this._apiLoader = document.createElement('google-js-api');
  176 + this._apiLoader.addEventListener('js-api-load', this.loadAuth2.bind(this));
  177 + },
  178 +
  179 + loadAuth2: function() {
  180 + gapi.load('auth2', this.initAuth2.bind(this));
  181 + },
  182 +
  183 + initAuth2: function() {
  184 + if (!('gapi' in window) || !('auth2' in window.gapi) || !this.clientId) {
  185 + return;
  186 + }
  187 + var auth = gapi.auth2.init({
  188 + 'client_id': this.clientId,
  189 + 'cookie_policy': this.cookiePolicy,
  190 + 'scope': this.requestedScopes,
  191 + 'hosted_domain': this.hostedDomain
  192 + });
  193 +
  194 + auth.currentUser.listen(this.handleUserUpdate.bind(this));
  195 +
  196 + auth.then(
  197 + function success() {
  198 + // Let the current user listener trigger the changes.
  199 + },
  200 + function error(error) {
  201 + console.error(error);
  202 + }
  203 + );
  204 + },
  205 +
  206 + handleUserUpdate: function(newPrimaryUser) {
  207 + // update and broadcast currentUser
  208 + var isSignedIn = newPrimaryUser.isSignedIn();
  209 + if (isSignedIn != this._signedIn) {
  210 + this._signedIn = isSignedIn;
  211 + for (var i=0; i<this.signinAwares.length; i++) {
  212 + this.signinAwares[i]._setSignedIn(isSignedIn);
  213 + }
  214 + }
  215 +
  216 + // update granted scopes
  217 + this._grantedScopeArray = this.strToScopeArray(
  218 + newPrimaryUser.getGrantedScopes());
  219 + // console.log(this._grantedScopeArray);
  220 + this.updateAdditionalAuth();
  221 +
  222 + var response = newPrimaryUser.getAuthResponse();
  223 + for (var i=0; i<this.signinAwares.length; i++) {
  224 + this.signinAwares[i]._updateScopeStatus(response);
  225 + }
  226 + },
  227 +
  228 + setOfflineCode: function(code) {
  229 + for (var i=0; i<this.signinAwares.length; i++) {
  230 + this.signinAwares[i]._updateOfflineCode(code);
  231 + }
  232 + },
  233 +
  234 + /** convert scope string to scope array */
  235 + strToScopeArray: function(str) {
  236 + if (!str) {
  237 + return [];
  238 + }
  239 + // remove extra spaces, then split
  240 + var scopes = str.replace(/\ +/g, ' ').trim().split(' ');
  241 + for (var i=0; i<scopes.length; i++) {
  242 + scopes[i] = scopes[i].toLowerCase();
  243 + // Handle scopes that will be deprecated but are still returned with their old value
  244 + if (scopes[i] === 'https://www.googleapis.com/auth/userinfo.profile') {
  245 + scopes[i] = 'profile';
  246 + }
  247 + if (scopes[i] === 'https://www.googleapis.com/auth/userinfo.email') {
  248 + scopes[i] = 'email';
  249 + }
  250 + }
  251 + // return with duplicates filtered out
  252 + return scopes.filter( function(value, index, self) {
  253 + return self.indexOf(value) === index;
  254 + });
  255 + },
  256 +
  257 + /** true if scopes have google+ scopes */
  258 + isPlusScope: function(scope) {
  259 + return (scope.indexOf('/auth/games') > -1)
  260 + || (scope.indexOf('auth/plus.') > -1 && scope.indexOf('auth/plus.me') < 0);
  261 + },
  262 +
  263 + /** true if scopes have been granted */
  264 + hasGrantedScopes: function(scopeStr) {
  265 + var scopes = this.strToScopeArray(scopeStr);
  266 + for (var i=0; i< scopes.length; i++) {
  267 + if (this._grantedScopeArray.indexOf(scopes[i]) === -1)
  268 + return false;
  269 + }
  270 + return true;
  271 + },
  272 +
  273 + /** request additional scopes */
  274 + requestScopes: function(newScopeStr) {
  275 + var newScopes = this.strToScopeArray(newScopeStr);
  276 + var scopesUpdated = false;
  277 + for (var i=0; i<newScopes.length; i++) {
  278 + if (this._requestedScopeArray.indexOf(newScopes[i]) === -1) {
  279 + this._requestedScopeArray.push(newScopes[i]);
  280 + scopesUpdated = true;
  281 + }
  282 + }
  283 + if (scopesUpdated) {
  284 + this.updateAdditionalAuth();
  285 + this.updatePlusScopes();
  286 + }
  287 + },
  288 +
  289 + /** update status of _needAdditionalAuth */
  290 + updateAdditionalAuth: function() {
  291 + var needMoreAuth = false;
  292 + if ((this.offlineAlwaysPrompt || this.offline ) && !this.offlineGranted) {
  293 + needMoreAuth = true;
  294 + } else {
  295 + for (var i=0; i<this._requestedScopeArray.length; i++) {
  296 + if (this._grantedScopeArray.indexOf(this._requestedScopeArray[i]) === -1) {
  297 + needMoreAuth = true;
  298 + break;
  299 + }
  300 + }
  301 + }
  302 + if (this._needAdditionalAuth != needMoreAuth) {
  303 + this._needAdditionalAuth = needMoreAuth;
  304 + // broadcast new value
  305 + for (var i=0; i<this.signinAwares.length; i++) {
  306 + this.signinAwares[i]._setNeedAdditionalAuth(needMoreAuth);
  307 + }
  308 + }
  309 + },
  310 +
  311 + updatePlusScopes: function() {
  312 + var hasPlusScopes = false;
  313 + for (var i = 0; i < this._requestedScopeArray.length; i++) {
  314 + if (this.isPlusScope(this._requestedScopeArray[i])) {
  315 + hasPlusScopes = true;
  316 + break;
  317 + }
  318 + }
  319 + if (this._hasPlusScopes != hasPlusScopes) {
  320 + this._hasPlusScopes = hasPlusScopes;
  321 + for (var i=0; i<this.signinAwares.length; i++) {
  322 + this.signinAwares[i]._setHasPlusScopes(hasPlusScopes);
  323 + }
  324 + }
  325 + },
  326 + /**
  327 + * attached <google-signin-aware>
  328 + * @param {<google-signin-aware>} aware element to add
  329 + */
  330 + attachSigninAware: function(aware) {
  331 + if (this.signinAwares.indexOf(aware) == -1) {
  332 + this.signinAwares.push(aware);
  333 + // Initialize aware properties
  334 + aware._setNeedAdditionalAuth(this._needAdditionalAuth);
  335 + aware._setSignedIn(this._signedIn);
  336 + aware._setHasPlusScopes(this._hasPlusScopes);
  337 + } else {
  338 + console.warn('signinAware attached more than once', aware);
  339 + }
  340 + },
  341 +
  342 + detachSigninAware: function(aware) {
  343 + var index = this.signinAwares.indexOf(aware);
  344 + if (index != -1) {
  345 + this.signinAwares.splice(index, 1);
  346 + } else {
  347 + console.warn('Trying to detach unattached signin-aware');
  348 + }
  349 + },
  350 +
  351 + /** returns scopes not granted */
  352 + getMissingScopes: function() {
  353 + return this._requestedScopeArray.filter( function(scope) {
  354 + return this._grantedScopeArray.indexOf(scope) === -1;
  355 + }.bind(this)).join(' ');
  356 + },
  357 +
  358 + assertAuthInitialized: function() {
  359 + if (!this.clientId) {
  360 + throw new Error("AuthEngine not initialized. clientId has not been configured.");
  361 + }
  362 + if (!('gapi' in window)) {
  363 + throw new Error("AuthEngine not initialized. gapi has not loaded.");
  364 + }
  365 + if (!('auth2' in window.gapi)) {
  366 + throw new Error("AuthEngine not initialized. auth2 not loaded.");
  367 + }
  368 + },
  369 +
  370 + /** pops up sign-in dialog */
  371 + signIn: function() {
  372 + this.assertAuthInitialized();
  373 + var params = {
  374 + 'scope': this.getMissingScopes()
  375 + };
  376 +
  377 + // Proxy specific attributes through to the signIn options.
  378 + Object.keys(ProxyLoginAttributes).forEach(function(key) {
  379 + if (this[key] && this[key] !== '') {
  380 + params[ProxyLoginAttributes[key]] = this[key];
  381 + }
  382 + }, this);
  383 +
  384 + var promise;
  385 + var user = gapi.auth2.getAuthInstance().currentUser.get();
  386 + if (!(this.offline || this.offlineAlwaysPrompt)) {
  387 + if (user.getGrantedScopes()) {
  388 + // additional auth, skip multiple account dialog
  389 + promise = user.grant(params);
  390 + } else {
  391 + // initial signin
  392 + promise = gapi.auth2.getAuthInstance().signIn(params);
  393 + }
  394 + } else {
  395 + params.redirect_uri = 'postmessage';
  396 + if (this.offlineAlwaysPrompt) {
  397 + params.approval_prompt = 'force';
  398 + }
  399 +
  400 + // Despite being documented at https://goo.gl/tiO0Bk
  401 + // It doesn't seem like user.grantOfflineAccess() actually exists in
  402 + // the current version of the Google Sign-In JS client we're using
  403 + // through GoogleWebComponents. So in the offline case, we will not
  404 + // distinguish between a first auth and an additional one.
  405 + promise = gapi.auth2.getAuthInstance().grantOfflineAccess(params);
  406 + }
  407 + promise.then(
  408 + function success(response) {
  409 + // If login was offline, response contains one string "code"
  410 + // Otherwise it contains the user object already
  411 + var newUser;
  412 + if (response.code) {
  413 + AuthEngine.offlineGranted = true;
  414 + newUser = gapi.auth2.getAuthInstance().currentUser.get();
  415 + AuthEngine.setOfflineCode(response.code);
  416 + } else {
  417 + newUser = response;
  418 + }
  419 +
  420 + var authResponse = newUser.getAuthResponse();
  421 + // Let the current user listener trigger the changes.
  422 + },
  423 + function error(error) {
  424 + if ("Access denied." == error.reason) {
  425 + // Access denied is not an error, user hit cancel
  426 + return;
  427 + } else {
  428 + console.error(error);
  429 + }
  430 + }
  431 + );
  432 + },
  433 +
  434 + /** signs user out */
  435 + signOut: function() {
  436 + this.assertAuthInitialized();
  437 + gapi.auth2.getAuthInstance().signOut().then(
  438 + function success() {
  439 + // Let the current user listener trigger the changes.
  440 + },
  441 + function error(error) {
  442 + console.error(error);
  443 + }
  444 + );
  445 + }
  446 + };
  447 +
  448 + AuthEngine.init();
  449 +
  450 +/**
  451 +`google-signin-aware` is used to enable authentication in custom elements by
  452 +interacting with a google-signin element that needs to be present somewhere
  453 +on the page.
  454 +
  455 +The `scopes` attribute allows you to specify which scope permissions are required
  456 +(e.g do you want to allow interaction with the Google Drive API).
  457 +
  458 +The `google-signin-aware-success` event is triggered when a user successfully
  459 +authenticates. If either `offline` or `offlineAlwaysPrompt` is set to true, successful
  460 +authentication will also trigger the `google-signin-offline-success`event.
  461 +The `google-signin-aware-signed-out` event is triggered when a user explicitly
  462 +signs out via the google-signin element.
  463 +
  464 +You can bind to `isAuthorized` property to monitor authorization state.
  465 +##### Example
  466 +
  467 + <google-signin-aware scopes="https://www.googleapis.com/auth/drive"></google-signin-aware>
  468 +
  469 +
  470 +##### Example with offline
  471 + <template id="awareness" is="dom-bind">
  472 + <google-signin-aware
  473 + scopes="https://www.googleapis.com/auth/drive"
  474 + offline
  475 + on-google-signin-aware-success="handleSignin"
  476 + on-google-signin-offline-success="handleOffline"></google-signin-aware>
  477 + <\/template>
  478 + <script>
  479 + var aware = document.querySelector('#awareness');
  480 + aware.handleSignin = function(response) {
  481 + var user = gapi.auth2.getAuthInstance().currentUser.get();
  482 + console.log('User name: ' + user.getBasicProfile().getName());
  483 + };
  484 + aware.handleOffline = function(response) {
  485 + console.log('Offline code received: ' + response.detail.code);
  486 + // Here you would POST response.detail.code to your webserver, which can
  487 + // exchange the authorization code for an access token. More info at:
  488 + // https://developers.google.com/identity/protocols/OAuth2WebServer
  489 + };
  490 + <\/script>
  491 +*/