Commit 525c13d8940ad0cb94ee66117553fe47ef6c4191
1 parent
ac237fdd
google component tests
Showing
24 changed files
with
2839 additions
and
0 deletions
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 | \ No newline at end of file | 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
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><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 →"> | ||
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><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 →"> | ||
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 | \ No newline at end of file | 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
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><google-signin></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><google-signin-aware></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><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>"></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 | +*/ | ||
492 | + Polymer({ | ||
493 | + | ||
494 | + is: 'google-signin-aware', | ||
495 | + | ||
496 | + /** | ||
497 | + * Fired when this scope has been authorized | ||
498 | + * @param {Object} result Authorization result. | ||
499 | + * @event google-signin-aware-success | ||
500 | + */ | ||
501 | + /** | ||
502 | + * Fired when an offline authorization is successful. | ||
503 | + * @param {Object} detail | ||
504 | + * @param {string} detail.code The one-time authorization code from Google. | ||
505 | + * Your application can exchange this for an `access_token` and `refresh_token` | ||
506 | + * @event google-signin-offline-success | ||
507 | + */ | ||
508 | + /** | ||
509 | + * Fired when this scope is not authorized | ||
510 | + * @event google-signin-aware-signed-out | ||
511 | + */ | ||
512 | + properties: { | ||
513 | + /** | ||
514 | + * App package name for android over-the-air installs. | ||
515 | + * See the relevant [docs](https://developers.google.com/+/web/signin/android-app-installs) | ||
516 | + */ | ||
517 | + appPackageName: { | ||
518 | + type: String, | ||
519 | + observer: '_appPackageNameChanged' | ||
520 | + }, | ||
521 | + /** | ||
522 | + * a Google Developers clientId reference | ||
523 | + */ | ||
524 | + clientId: { | ||
525 | + type: String, | ||
526 | + observer: '_clientIdChanged' | ||
527 | + }, | ||
528 | + | ||
529 | + /** | ||
530 | + * The cookie policy defines what URIs have access to the session cookie | ||
531 | + * remembering the user's sign-in state. | ||
532 | + * See the relevant [docs](https://developers.google.com/+/web/signin/reference#determining_a_value_for_cookie_policy) for more information. | ||
533 | + * @default 'single_host_origin' | ||
534 | + */ | ||
535 | + cookiePolicy: { | ||
536 | + type: String, | ||
537 | + observer: '_cookiePolicyChanged' | ||
538 | + }, | ||
539 | + | ||
540 | + /** | ||
541 | + * The app activity types you want to write on behalf of the user | ||
542 | + * (e.g http://schemas.google.com/AddActivity) | ||
543 | + * | ||
544 | + */ | ||
545 | + requestVisibleActions: { | ||
546 | + type: String, | ||
547 | + observer: '_requestVisibleActionsChanged' | ||
548 | + }, | ||
549 | + | ||
550 | + /** | ||
551 | + * The Google Apps domain to which users must belong to sign in. | ||
552 | + * See the relevant [docs](https://developers.google.com/identity/sign-in/web/reference) for more information. | ||
553 | + */ | ||
554 | + hostedDomain: { | ||
555 | + type: String, | ||
556 | + observer: '_hostedDomainChanged' | ||
557 | + }, | ||
558 | + | ||
559 | + /** | ||
560 | + * Allows for offline `access_token` retrieval during the signin process. | ||
561 | + * See also `offlineAlwaysPrompt`. You only need to set one of the two; if both | ||
562 | + * are set, the behavior of `offlineAlwaysPrompt` will override `offline`. | ||
563 | + */ | ||
564 | + offline: { | ||
565 | + type: Boolean, | ||
566 | + value: false, | ||
567 | + observer: '_offlineChanged' | ||
568 | + }, | ||
569 | + | ||
570 | + /** | ||
571 | + * Works the same as `offline` with the addition that it will always | ||
572 | + * force a re-prompt to the user, guaranteeing that you will get a | ||
573 | + * refresh_token even if the user has already granted offline access to | ||
574 | + * this application. You only need to set one of `offline` or | ||
575 | + * `offlineAlwaysPrompt`, not both. | ||
576 | + */ | ||
577 | + offlineAlwaysPrompt: { | ||
578 | + type: Boolean, | ||
579 | + value: false, | ||
580 | + observer: '_offlineAlwaysPromptChanged' | ||
581 | + }, | ||
582 | + | ||
583 | + /** | ||
584 | + * The scopes to provide access to (e.g https://www.googleapis.com/auth/drive) | ||
585 | + * and should be space-delimited. | ||
586 | + */ | ||
587 | + scopes: { | ||
588 | + type: String, | ||
589 | + value: 'profile', | ||
590 | + observer: '_scopesChanged' | ||
591 | + }, | ||
592 | + | ||
593 | + /** | ||
594 | + * True if user is signed in | ||
595 | + */ | ||
596 | + signedIn: { | ||
597 | + type: Boolean, | ||
598 | + notify: true, | ||
599 | + readOnly: true | ||
600 | + }, | ||
601 | + | ||
602 | + /** | ||
603 | + * True if authorizations for *this* element have been granted | ||
604 | + */ | ||
605 | + isAuthorized: { | ||
606 | + type: Boolean, | ||
607 | + notify: true, | ||
608 | + readOnly: true, | ||
609 | + value: false | ||
610 | + }, | ||
611 | + | ||
612 | + /** | ||
613 | + * True if additional authorizations for *any* element are required | ||
614 | + */ | ||
615 | + needAdditionalAuth: { | ||
616 | + type: Boolean, | ||
617 | + notify: true, | ||
618 | + readOnly: true | ||
619 | + }, | ||
620 | + | ||
621 | + /** | ||
622 | + * True if *any* element has google+ scopes | ||
623 | + */ | ||
624 | + hasPlusScopes: { | ||
625 | + type: Boolean, | ||
626 | + value: false, | ||
627 | + notify: true, | ||
628 | + readOnly: true | ||
629 | + } | ||
630 | + }, | ||
631 | + | ||
632 | + attached: function() { | ||
633 | + AuthEngine.attachSigninAware(this); | ||
634 | + }, | ||
635 | + | ||
636 | + detached: function() { | ||
637 | + AuthEngine.detachSigninAware(this); | ||
638 | + }, | ||
639 | + | ||
640 | + /** pops up the authorization dialog */ | ||
641 | + signIn: function() { | ||
642 | + AuthEngine.signIn(); | ||
643 | + }, | ||
644 | + | ||
645 | + /** signs user out */ | ||
646 | + signOut: function() { | ||
647 | + AuthEngine.signOut(); | ||
648 | + }, | ||
649 | + | ||
650 | + _appPackageNameChanged: function(newName, oldName) { | ||
651 | + AuthEngine.appPackageName = newName; | ||
652 | + }, | ||
653 | + | ||
654 | + _clientIdChanged: function(newId, oldId) { | ||
655 | + AuthEngine.clientId = newId; | ||
656 | + }, | ||
657 | + | ||
658 | + _cookiePolicyChanged: function(newPolicy, oldPolicy) { | ||
659 | + AuthEngine.cookiePolicy = newPolicy; | ||
660 | + }, | ||
661 | + | ||
662 | + _requestVisibleActionsChanged: function(newVal, oldVal) { | ||
663 | + AuthEngine.requestVisibleActions = newVal; | ||
664 | + }, | ||
665 | + | ||
666 | + _hostedDomainChanged: function(newVal, oldVal) { | ||
667 | + AuthEngine.hostedDomain = newVal; | ||
668 | + }, | ||
669 | + | ||
670 | + _offlineChanged: function(newVal, oldVal) { | ||
671 | + AuthEngine.offline = newVal; | ||
672 | + }, | ||
673 | + | ||
674 | + _offlineAlwaysPromptChanged: function(newVal, oldVal) { | ||
675 | + AuthEngine.offlineAlwaysPrompt = newVal; | ||
676 | + }, | ||
677 | + | ||
678 | + _scopesChanged: function(newVal, oldVal) { | ||
679 | + AuthEngine.requestScopes(newVal); | ||
680 | + this._updateScopeStatus(); | ||
681 | + }, | ||
682 | + | ||
683 | + _updateScopeStatus: function(user) { | ||
684 | + var newAuthorized = this.signedIn && AuthEngine.hasGrantedScopes(this.scopes); | ||
685 | + if (newAuthorized !== this.isAuthorized) { | ||
686 | + this._setIsAuthorized(newAuthorized); | ||
687 | + if (newAuthorized) { | ||
688 | + this.fire('google-signin-aware-success', user); | ||
689 | + } | ||
690 | + else { | ||
691 | + this.fire('google-signin-aware-signed-out', user); | ||
692 | + } | ||
693 | + } | ||
694 | + }, | ||
695 | + | ||
696 | + _updateOfflineCode: function(code) { | ||
697 | + if (code) { | ||
698 | + this.fire('google-signin-offline-success', {code: code}); | ||
699 | + } | ||
700 | + } | ||
701 | + }); | ||
702 | + })(); | ||
703 | +</script> |
bower_components/google-signin/google-signin.css
0 → 100644
1 | +:host { | ||
2 | + display: inline-block; | ||
3 | + position: relative; | ||
4 | + box-sizing: border-box; | ||
5 | + margin: 0 0.29em; | ||
6 | + background: transparent; | ||
7 | + text-align: center; | ||
8 | + font: inherit; | ||
9 | + outline: none; | ||
10 | + border-radius: 3px; | ||
11 | + -webkit-user-select: none; | ||
12 | + user-select: none; | ||
13 | + cursor: pointer; | ||
14 | + z-index: 0; | ||
15 | +} | ||
16 | + | ||
17 | +:host([disabled]) { | ||
18 | + cursor: auto; | ||
19 | + pointer-events: none; | ||
20 | +} | ||
21 | + | ||
22 | +:host([disabled]) #button { | ||
23 | + background: #eaeaea; | ||
24 | + color: #a8a8a8; | ||
25 | +} | ||
26 | + | ||
27 | +#button { | ||
28 | + position: relative; | ||
29 | + outline: none; | ||
30 | + font-size: 14px; | ||
31 | + font-weight: 400; | ||
32 | + font-family: 'RobotoDraft','Roboto',arial,sans-serif; | ||
33 | + white-space: nowrap; | ||
34 | + border-radius: inherit; | ||
35 | +} | ||
36 | + | ||
37 | +iron-icon { | ||
38 | + width: 22px; | ||
39 | + height: 22px; | ||
40 | + margin: 6px; | ||
41 | +} | ||
42 | + | ||
43 | +.icon { | ||
44 | + display: inline-block; | ||
45 | + vertical-align: middle; | ||
46 | +} | ||
47 | + | ||
48 | +#shadow { | ||
49 | + border-radius: inherit; | ||
50 | +} | ||
51 | + | ||
52 | +#ripple { | ||
53 | + pointer-events: none; | ||
54 | +} | ||
55 | + | ||
56 | +.button-content { | ||
57 | + outline: none; | ||
58 | +} | ||
59 | + | ||
60 | +.buttonText { | ||
61 | + display: inline-block; | ||
62 | + vertical-align: middle; | ||
63 | + padding-right: .8em; | ||
64 | +} | ||
65 | + | ||
66 | +/* | ||
67 | + * Dark Theme | ||
68 | + */ | ||
69 | +.theme-dark { | ||
70 | + background: #da4336; | ||
71 | + color: #ffffff; | ||
72 | + border: 1px solid transparent; | ||
73 | +} | ||
74 | + | ||
75 | +.theme-dark.signedIn-true.additionalAuth-false { | ||
76 | + background: #999; | ||
77 | + border: 1px solid #888; | ||
78 | +} | ||
79 | + | ||
80 | +.theme-dark.signedIn-true.additionalAuth-false:hover, | ||
81 | +.theme-dark.signedIn-true.additionalAuth-false:focus { | ||
82 | + background: #aaa; | ||
83 | +} | ||
84 | + | ||
85 | +:host([noink]) .theme-dark:hover, | ||
86 | +:host([noink]) .theme-dark:focus { | ||
87 | + background: #e74b37; | ||
88 | +} | ||
89 | + | ||
90 | +:host([noink]) .theme-dark.signedIn-true.additionalAuth-false:hover, | ||
91 | +:host([noink]) .theme-dark.signedIn-true.additionalAuth-false:focus { | ||
92 | + background: #aaa; | ||
93 | +} | ||
94 | + | ||
95 | +/* | ||
96 | + * Light Theme | ||
97 | + */ | ||
98 | +.theme-light { | ||
99 | + background: #fff; | ||
100 | + color: #737373; | ||
101 | + border: 1px solid #d9d9d9; | ||
102 | +} | ||
103 | + | ||
104 | +.theme-light.signedIn-true.additionalAuth-false { | ||
105 | + background: #c0c0c0; | ||
106 | + color: #fff; | ||
107 | + border: #888 1px solid; | ||
108 | +} | ||
109 | + | ||
110 | +.theme-light.signedIn-true.additionalAuth-false:hover, | ||
111 | +.theme-light.signedIn-true.additionalAuth-false:focus { | ||
112 | + background: #aaa; | ||
113 | +} | ||
114 | + | ||
115 | +:host([noink]) .theme-light .button-content:hover, | ||
116 | +:host([noink]) .theme-light:focus { | ||
117 | + border: 1px solid #c0c0c0; | ||
118 | +} | ||
119 | + | ||
120 | +:host([noink]) .theme-light.signedIn-true.additionalAuth-false:hover, | ||
121 | +:host([noink]) .theme-light.signedIn-true.additionalAuth-false:focus { | ||
122 | + background: #aaa; | ||
123 | +} | ||
124 | + | ||
125 | +/* | ||
126 | + * Icon Only Width | ||
127 | + */ | ||
128 | +.width-iconOnly .buttonText { | ||
129 | + display: none; | ||
130 | +} | ||
131 | + | ||
132 | +/* | ||
133 | + * Tall Height | ||
134 | + */ | ||
135 | +.height-tall .buttonText { | ||
136 | + font-size: 15px; | ||
137 | + font-weight: 700; | ||
138 | +} | ||
139 | + | ||
140 | +.height-tall iron-icon { | ||
141 | + width: 30px; | ||
142 | + height: 30px; | ||
143 | + margin: 8px; | ||
144 | +} | ||
145 | + | ||
146 | +/* | ||
147 | + * Short Height | ||
148 | + */ | ||
149 | +.height-short .buttonText { | ||
150 | + font-size: 11px; | ||
151 | +} | ||
152 | + | ||
153 | +.height-short iron-icon { | ||
154 | + width: 16px; | ||
155 | + height: 16px; | ||
156 | + margin: 3px; | ||
157 | +} | ||
158 | + | ||
159 | + | ||
160 | +/* | ||
161 | + * Branding | ||
162 | + */ | ||
163 | + | ||
164 | +/* Google Scopes */ | ||
165 | + | ||
166 | +/* Dark Theme */ | ||
167 | +.brand-google.theme-dark { | ||
168 | + background: #4184F3; | ||
169 | + color: #fff; | ||
170 | + border: 1px solid #3266d5; | ||
171 | +} | ||
172 | + | ||
173 | +.brand-google.theme-dark #ripple { | ||
174 | + color: #1b39a8; | ||
175 | +} | ||
176 | + | ||
177 | +:host([noink]) .brand-google.theme-dark:hover, | ||
178 | +:host([noink]) .brand-google.theme-dark:focus { | ||
179 | + background: #e74b37; | ||
180 | +} | ||
181 | + | ||
182 | +.brand-google.theme-light .icon { | ||
183 | + color: #4184F3; | ||
184 | +} | ||
185 | + | ||
186 | +.brand-google.theme-light.signedIn-true.additionalAuth-false .icon { | ||
187 | + color: #fff; | ||
188 | +} | ||
189 | + | ||
190 | +.brand-google.theme-light #ripple { | ||
191 | + color: #444; | ||
192 | +} | ||
193 | + | ||
194 | +:host([noink]) .brand-google.theme-light:hover, | ||
195 | +:host([noink]) .brand-google.theme-light:focus { | ||
196 | + border: 1px solid #c0c0c0; | ||
197 | +} | ||
198 | + | ||
199 | +.brand-google-plus.theme-dark { | ||
200 | + background: #da4336; | ||
201 | + color: #fff; | ||
202 | + border: 1px solid transparent; | ||
203 | +} | ||
204 | + | ||
205 | +.brand-google-plus.theme-dark #ripple { | ||
206 | + color: #c43828; | ||
207 | +} | ||
208 | + | ||
209 | +/* Light Theme */ | ||
210 | +.brand-google-plus.theme-light { | ||
211 | + background: #fff; | ||
212 | + color: #737373; | ||
213 | + border: 1px solid #d9d9d9; | ||
214 | +} | ||
215 | + | ||
216 | +.brand-google-plus.theme-light .icon { | ||
217 | + color: #e74b37; | ||
218 | +} | ||
219 | + | ||
220 | +.brand-google-plus.theme-light.signedIn-true.additionalAuth-false .icon { | ||
221 | + color: #fff; | ||
222 | +} | ||
223 | + | ||
224 | +.brand-google-plus.theme-light #ripple { | ||
225 | + color: #400; | ||
226 | +} | ||
227 | + | ||
228 | +:host([noink]) .brand-google-plus.theme-light:hover, | ||
229 | +:host([noink]) .brand-google-plus.theme-light:focus { | ||
230 | + border: 1px solid #c0c0c0; | ||
231 | +} |
bower_components/google-signin/google-signin.html
0 → 100644
1 | +<link rel="import" href="../polymer/polymer.html"> | ||
2 | +<link rel="import" href="google-signin-aware.html"> | ||
3 | +<link rel="import" href="../iron-icon/iron-icon.html"> | ||
4 | +<link rel="import" href="../iron-icons/iron-icons.html"> | ||
5 | +<link rel="import" href="../font-roboto/roboto.html"> | ||
6 | +<link rel="import" href="../google-apis/google-js-api.html"> | ||
7 | +<link rel="import" href="../paper-ripple/paper-ripple.html"> | ||
8 | +<link rel="import" href="../paper-material/paper-material.html"> | ||
9 | +<link rel="import" href="../iron-flex-layout/classes/iron-flex-layout.html"> | ||
10 | +<link rel="import" href="google-icons.html"> | ||
11 | + | ||
12 | +<dom-module id="google-signin"> | ||
13 | + <link rel="import" type="css" href="google-signin.css"> | ||
14 | + <template> | ||
15 | + <google-signin-aware id="aware" | ||
16 | + app-package-name="{{appPackageName}}" | ||
17 | + client-id="{{clientId}}" | ||
18 | + cookie-policy="{{cookiePolicy}}" | ||
19 | + request-visible-actions="{{requestVisibleActions}}" | ||
20 | + hosted-domain="{{hostedDomain}}" | ||
21 | + offline="{{offline}}" | ||
22 | + offline-always-prompt="{{offlineAlwaysPrompt}}" | ||
23 | + scopes="{{scopes}}" | ||
24 | + signed-in="{{signedIn}}" | ||
25 | + is-authorized="{{isAuthorized}}" | ||
26 | + need-additional-auth="{{needAdditionalAuth}}" | ||
27 | + has-plus-scopes="{{hasPlusScopes}}"></google-signin-aware> | ||
28 | + <template is="dom-if" if="{{raised}}"> | ||
29 | + <paper-material id="shadow" class="fit" elevation="2" animated></paper-material> | ||
30 | + </template> | ||
31 | + <div id="button" | ||
32 | + class$="[[_computeButtonClass(height, width, theme, signedIn, _brand, needAdditionalAuth)]]"> | ||
33 | + | ||
34 | + <paper-ripple id="ripple" class="fit"></paper-ripple> | ||
35 | + <!-- this div is needed to position the ripple behind text content --> | ||
36 | + <div relative layout horizontal center-center> | ||
37 | + <template is="dom-if" if="{{_computeButtonIsSignIn(signedIn, needAdditionalAuth)}}"> | ||
38 | + <div class="button-content signIn" tabindex="0" | ||
39 | + on-click="signIn" on-keydown="_signInKeyPress"> | ||
40 | + <span class="icon"><iron-icon icon="[[_brandIcon]]"></iron-icon></span> | ||
41 | + <span class="buttonText">{{_labelSignin}}</span> | ||
42 | + </div> | ||
43 | + </template> | ||
44 | + <template is="dom-if" if="{{_computeButtonIsSignOut(signedIn, needAdditionalAuth) }}"> | ||
45 | + <div class="button-content signOut" tabindex="0" | ||
46 | + on-click="signOut" on-keydown="_signOutKeyPress"> | ||
47 | + <span class="icon"><iron-icon icon="[[_brandIcon]]"></iron-icon></span> | ||
48 | + <span class="buttonText">{{labelSignout}}</span> | ||
49 | + </div> | ||
50 | + </template> | ||
51 | + <template is="dom-if" if="{{_computeButtonIsSignOutAddl(signedIn, needAdditionalAuth) }}"> | ||
52 | + <div class="button-content signIn" tabindex="0" | ||
53 | + on-click="signIn" on-keydown="_signInKeyPress"> | ||
54 | + <span class="icon"><iron-icon icon="[[_brandIcon]]"></iron-icon></span> | ||
55 | + <span class="buttonText">{{labelAdditional}}</span> | ||
56 | + </div> | ||
57 | + </template> | ||
58 | + </div> | ||
59 | + | ||
60 | + </div> | ||
61 | + </template> | ||
62 | +</dom-module> | ||
63 | +<script> | ||
64 | + (function() { | ||
65 | + | ||
66 | + /** | ||
67 | + * Enum brand values. | ||
68 | + * @readonly | ||
69 | + * @enum {string} | ||
70 | + */ | ||
71 | + var BrandValue = { | ||
72 | + GOOGLE: 'google', | ||
73 | + PLUS: 'google-plus' | ||
74 | + }; | ||
75 | + | ||
76 | + /** | ||
77 | + * Enum height values. | ||
78 | + * @readonly | ||
79 | + * @enum {string} | ||
80 | + */ | ||
81 | + var HeightValue = { | ||
82 | + SHORT: 'short', | ||
83 | + STANDARD: 'standard', | ||
84 | + TALL: 'tall' | ||
85 | + }; | ||
86 | + | ||
87 | + /** | ||
88 | + * Enum button label default values. | ||
89 | + * @readonly | ||
90 | + * @enum {string} | ||
91 | + */ | ||
92 | + var LabelValue = { | ||
93 | + STANDARD: 'Sign in', | ||
94 | + WIDE: 'Sign in with Google', | ||
95 | + WIDE_PLUS: 'Sign in with Google+' | ||
96 | + }; | ||
97 | + | ||
98 | + /** | ||
99 | + * Enum theme values. | ||
100 | + * @readonly | ||
101 | + * @enum {string} | ||
102 | + */ | ||
103 | + var ThemeValue = { | ||
104 | + LIGHT: 'light', | ||
105 | + DARK: 'dark' | ||
106 | + }; | ||
107 | + | ||
108 | + /** | ||
109 | + * Enum width values. | ||
110 | + * @readonly | ||
111 | + * @enum {string} | ||
112 | + */ | ||
113 | + var WidthValue = { | ||
114 | + ICON_ONLY: 'iconOnly', | ||
115 | + STANDARD: 'standard', | ||
116 | + WIDE: 'wide' | ||
117 | + }; | ||
118 | + | ||
119 | +/** | ||
120 | +<google-signin> is used to authenticate with Google, allowing you to interact | ||
121 | +with other Google APIs such as Drive and Google+. | ||
122 | + | ||
123 | +<img style="max-width:100%;" src="https://cloud.githubusercontent.com/assets/107076/6791176/5c868822-d16a-11e4-918c-ec9b84a2db45.png"/> | ||
124 | + | ||
125 | +If you do not need to show the button, use companion `<google-signin-aware>` element to declare scopes, check authentication state. | ||
126 | + | ||
127 | +#### Examples | ||
128 | + | ||
129 | + <google-signin client-id="..." scopes="https://www.googleapis.com/auth/drive"></google-signin> | ||
130 | + | ||
131 | + <google-signin label-signin="Sign-in" client-id="..." scopes="https://www.googleapis.com/auth/drive"></google-signin> | ||
132 | + | ||
133 | + <google-signin theme="dark" width="iconOnly" client-id="..." scopes="https://www.googleapis.com/auth/drive"></google-signin> | ||
134 | + | ||
135 | + | ||
136 | +#### Notes | ||
137 | + | ||
138 | +The attribute `clientId` is provided in your Google Developers Console | ||
139 | +(https://console.developers.google.com). | ||
140 | + | ||
141 | +The `scopes` attribute allows you to specify which scope permissions are required | ||
142 | +(e.g do you want to allow interaction with the Google Drive API). Many APIs also | ||
143 | +need to be enabled in the Google Developers Console before you can use them. | ||
144 | + | ||
145 | +The `requestVisibleActions` attribute is necessary if you want to write app | ||
146 | +activities (https://developers.google.com/+/web/app-activities/) on behalf of | ||
147 | +the user. Please note that this attribute is only valid in combination with the | ||
148 | +plus.login scope (https://www.googleapis.com/auth/plus.login). | ||
149 | + | ||
150 | +The `offline` attribute allows you to get an auth code which your server can | ||
151 | +redeem for an offline access token | ||
152 | +(https://developers.google.com/identity/sign-in/web/server-side-flow). | ||
153 | +You can also set `offline-always-prompt` instead of `offline` to ensure that your app | ||
154 | +will re-prompt the user for offline access and generate a working `refresh_token` | ||
155 | +even if they have already granted offline access to your app in the past. | ||
156 | + | ||
157 | +Use label properties to customize prompts. | ||
158 | + | ||
159 | +The button can be styled in using the `height`, `width`, and `theme` attributes. | ||
160 | +These attributes help you follow the Google+ Sign-In button branding guidelines | ||
161 | +(https://developers.google.com/+/branding-guidelines). | ||
162 | + | ||
163 | +The `google-signin-success` event is triggered when a user successfully authenticates | ||
164 | +and `google-signed-out` is triggered when user signs out. | ||
165 | +You can also use `isAuthorized` attribute to observe user's authentication state. | ||
166 | + | ||
167 | +Additional events, such as `google-signout-attempted` are | ||
168 | +triggered when the user attempts to sign-out and successfully signs out. | ||
169 | + | ||
170 | +When requesting offline access, the `google-signin-offline-success` event is | ||
171 | +triggered when the user successfully consents with offline support. | ||
172 | + | ||
173 | +The `google-signin-necessary` event is fired when scopes requested via | ||
174 | +google-signin-aware elements require additional user permissions. | ||
175 | + | ||
176 | +#### Testing | ||
177 | + | ||
178 | +By default, the demo accompanying this element is setup to work on localhost with | ||
179 | +port 8080. That said, you *should* update the `clientId` to your own one for | ||
180 | +any apps you're building. See the Google Developers Console | ||
181 | +(https://console.developers.google.com) for more info. | ||
182 | + | ||
183 | +@demo | ||
184 | +*/ | ||
185 | + | ||
186 | + Polymer({ | ||
187 | + | ||
188 | + is: 'google-signin', | ||
189 | + | ||
190 | + /** | ||
191 | + * Fired when user is signed in. | ||
192 | + * You can use auth2 api to retrieve current user: `gapi.auth2.getAuthInstance().currentUser.get();` | ||
193 | + * @event google-signin-success | ||
194 | + */ | ||
195 | + | ||
196 | + /** | ||
197 | + * Fired when the user is signed-out. | ||
198 | + * @event google-signed-out | ||
199 | + */ | ||
200 | + | ||
201 | + /** | ||
202 | + * Fired if user requires additional authorization | ||
203 | + * @event google-signin-necessary | ||
204 | + */ | ||
205 | + | ||
206 | + /** | ||
207 | + * Fired when signed in, and scope has been authorized | ||
208 | + * @param {Object} result Authorization result. | ||
209 | + * @event google-signin-aware-success | ||
210 | + */ | ||
211 | + | ||
212 | + /** | ||
213 | + * Fired when an offline authorization is successful. | ||
214 | + * @event google-signin-offline-success | ||
215 | + * @param {Object} detail | ||
216 | + * @param {string} detail.code The one-time authorization code from Google. | ||
217 | + * Your application can exchange this for an `access_token` and `refresh_token` | ||
218 | + */ | ||
219 | + | ||
220 | + /** | ||
221 | + * Fired when this scope is not authorized | ||
222 | + * @event google-signin-aware-signed-out | ||
223 | + */ | ||
224 | + properties: { | ||
225 | + /** | ||
226 | + * App package name for android over-the-air installs. | ||
227 | + * See the relevant [docs](https://developers.google.com/+/web/signin/android-app-installs) | ||
228 | + */ | ||
229 | + appPackageName: { | ||
230 | + type: String, | ||
231 | + value: '' | ||
232 | + }, | ||
233 | + | ||
234 | + /** | ||
235 | + * The brand being used for logo and styling. | ||
236 | + * | ||
237 | + * @default 'google' | ||
238 | + */ | ||
239 | + brand: { | ||
240 | + type: String, | ||
241 | + value: '' | ||
242 | + }, | ||
243 | + | ||
244 | + /** @private */ | ||
245 | + _brand: { | ||
246 | + type: String, | ||
247 | + computed: '_computeBrand(brand, hasPlusScopes)' | ||
248 | + }, | ||
249 | + | ||
250 | + /** | ||
251 | + * a Google Developers clientId reference | ||
252 | + */ | ||
253 | + clientId: { | ||
254 | + type: String, | ||
255 | + value: '' | ||
256 | + }, | ||
257 | + | ||
258 | + /** | ||
259 | + * The cookie policy defines what URIs have access to the session cookie | ||
260 | + * remembering the user's sign-in state. | ||
261 | + * See the relevant [docs](https://developers.google.com/+/web/signin/reference#determining_a_value_for_cookie_policy) for more information. | ||
262 | + * | ||
263 | + * @default 'single_host_origin' | ||
264 | + */ | ||
265 | + cookiePolicy: { | ||
266 | + type: String, | ||
267 | + value: '' | ||
268 | + }, | ||
269 | + | ||
270 | + /** | ||
271 | + * The height to use for the button. | ||
272 | + * | ||
273 | + * Available options: short, standard, tall. | ||
274 | + * | ||
275 | + * @type {HeightValue} | ||
276 | + */ | ||
277 | + height: { | ||
278 | + type: String, | ||
279 | + value: 'standard' | ||
280 | + }, | ||
281 | + | ||
282 | + /** | ||
283 | + * By default the ripple expands to fill the button. Set this to true to | ||
284 | + * constrain the ripple to a circle within the button. | ||
285 | + */ | ||
286 | + fill: { | ||
287 | + type: Boolean, | ||
288 | + value: true | ||
289 | + }, | ||
290 | + | ||
291 | + /** | ||
292 | + * An optional label for the button for additional permissions. | ||
293 | + */ | ||
294 | + labelAdditional: { | ||
295 | + type: String, | ||
296 | + value: 'Additional permissions required' | ||
297 | + }, | ||
298 | + | ||
299 | + /** | ||
300 | + * An optional label for the sign-in button. | ||
301 | + */ | ||
302 | + labelSignin: { | ||
303 | + type: String, | ||
304 | + value: '' | ||
305 | + }, | ||
306 | + | ||
307 | + _labelSignin: { | ||
308 | + type: String, | ||
309 | + computed: '_computeSigninLabel(labelSignin, width, _brand)' | ||
310 | + }, | ||
311 | + | ||
312 | + /** | ||
313 | + * An optional label for the sign-out button. | ||
314 | + */ | ||
315 | + labelSignout: { | ||
316 | + type: String, | ||
317 | + value: 'Sign out' | ||
318 | + }, | ||
319 | + | ||
320 | + /** | ||
321 | + * If true, the button will be styled with a shadow. | ||
322 | + */ | ||
323 | + raised: { | ||
324 | + type: Boolean, | ||
325 | + value: false | ||
326 | + }, | ||
327 | + | ||
328 | + /** | ||
329 | + * The app activity types you want to write on behalf of the user | ||
330 | + * (e.g http://schemas.google.com/AddActivity) | ||
331 | + */ | ||
332 | + requestVisibleActions: { | ||
333 | + type: String, | ||
334 | + value: '' | ||
335 | + }, | ||
336 | + | ||
337 | + /** | ||
338 | + * The Google Apps domain to which users must belong to sign in. | ||
339 | + * See the relevant [docs](https://developers.google.com/identity/sign-in/web/reference) for more information. | ||
340 | + */ | ||
341 | + hostedDomain: { | ||
342 | + type: String, | ||
343 | + value: '' | ||
344 | + }, | ||
345 | + | ||
346 | + /** | ||
347 | + * Allows for offline `access_token` retrieval during the signin process. | ||
348 | + */ | ||
349 | + offline: { | ||
350 | + type: Boolean, | ||
351 | + value: false | ||
352 | + }, | ||
353 | + | ||
354 | + /** | ||
355 | + * Forces a re-prompt, even if the user has already granted offline | ||
356 | + * access to your application in the past. You only need one of | ||
357 | + * `offline` and `offlineAlwaysPrompt`. | ||
358 | + */ | ||
359 | + offlineAlwaysPrompt: { | ||
360 | + type: Boolean, | ||
361 | + value: false | ||
362 | + }, | ||
363 | + | ||
364 | + /** | ||
365 | + * The scopes to provide access to (e.g https://www.googleapis.com/auth/drive) | ||
366 | + * and should be space-delimited. | ||
367 | + */ | ||
368 | + scopes: { | ||
369 | + type: String, | ||
370 | + value: '' | ||
371 | + }, | ||
372 | + | ||
373 | + /** | ||
374 | + * The theme to use for the button. | ||
375 | + * | ||
376 | + * Available options: light, dark. | ||
377 | + * | ||
378 | + * @attribute theme | ||
379 | + * @type {ThemeValue} | ||
380 | + * @default 'dark' | ||
381 | + */ | ||
382 | + theme: { | ||
383 | + type: String, | ||
384 | + value: 'dark' | ||
385 | + }, | ||
386 | + | ||
387 | + /** | ||
388 | + * The width to use for the button. | ||
389 | + * | ||
390 | + * Available options: iconOnly, standard, wide. | ||
391 | + * | ||
392 | + * @type {WidthValue} | ||
393 | + */ | ||
394 | + width: { | ||
395 | + type: String, | ||
396 | + value: 'standard' | ||
397 | + }, | ||
398 | + | ||
399 | + _brandIcon: { | ||
400 | + type: String, | ||
401 | + computed: '_computeIcon(_brand)' | ||
402 | + }, | ||
403 | + | ||
404 | + /** | ||
405 | + * True if *any* element has google+ scopes | ||
406 | + */ | ||
407 | + hasPlusScopes: { | ||
408 | + type: Boolean, | ||
409 | + notify: true, | ||
410 | + value: false | ||
411 | + }, | ||
412 | + | ||
413 | + /** | ||
414 | + * True if additional authorization required globally | ||
415 | + */ | ||
416 | + needAdditionalAuth: { | ||
417 | + type: Boolean, | ||
418 | + value: false | ||
419 | + }, | ||
420 | + | ||
421 | + /** | ||
422 | + * Is user signed in? | ||
423 | + */ | ||
424 | + signedIn: { | ||
425 | + type: Boolean, | ||
426 | + notify: true, | ||
427 | + value: false, | ||
428 | + observer: '_observeSignedIn' | ||
429 | + }, | ||
430 | + | ||
431 | + /** | ||
432 | + * True if authorizations for *this* element have been granted | ||
433 | + */ | ||
434 | + isAuthorized: { | ||
435 | + type: Boolean, | ||
436 | + notify: true, | ||
437 | + value: false | ||
438 | + } | ||
439 | + | ||
440 | + }, | ||
441 | + | ||
442 | + _computeButtonClass: function(height, width, theme, signedIn, brand, needAdditionalAuth) { | ||
443 | + return "height-" + height + " width-" + width + " theme-" + theme + " signedIn-" + signedIn + " brand-" + brand + " additionalAuth-" + needAdditionalAuth; | ||
444 | + }, | ||
445 | + | ||
446 | + _computeIcon: function(brand) { | ||
447 | + return "google:" + brand; | ||
448 | + }, | ||
449 | + | ||
450 | + /* Button state computed */ | ||
451 | + _computeButtonIsSignIn: function(signedIn, additionalAuth) { | ||
452 | + return !signedIn; | ||
453 | + }, | ||
454 | + | ||
455 | + _computeButtonIsSignOut: function(signedIn, additionalAuth) { | ||
456 | + return signedIn && !additionalAuth; | ||
457 | + }, | ||
458 | + | ||
459 | + _computeButtonIsSignOutAddl: function(signedIn, additionalAuth) { | ||
460 | + return signedIn && additionalAuth; | ||
461 | + }, | ||
462 | + | ||
463 | + _computeBrand: function(attrBrand, hasPlusScopes) { | ||
464 | + var newBrand; | ||
465 | + if (attrBrand) { | ||
466 | + newBrand = attrBrand; | ||
467 | + } else if (hasPlusScopes) { | ||
468 | + newBrand = BrandValue.PLUS; | ||
469 | + } else { | ||
470 | + newBrand = BrandValue.GOOGLE; | ||
471 | + }; | ||
472 | + return newBrand; | ||
473 | + }, | ||
474 | + | ||
475 | + _observeSignedIn: function(newVal, oldVal) { | ||
476 | + if (newVal) { | ||
477 | + if (this.needAdditionalAuth) | ||
478 | + this.fire('google-signin-necessary'); | ||
479 | + this.fire('google-signin-success'); | ||
480 | + } | ||
481 | + else | ||
482 | + this.fire('google-signed-out'); | ||
483 | + }, | ||
484 | + | ||
485 | + /** | ||
486 | + * Determines the proper label based on the attributes. | ||
487 | + */ | ||
488 | + _computeSigninLabel: function(labelSignin, width, _brand) { | ||
489 | + if (labelSignin) { | ||
490 | + return labelSignin; | ||
491 | + } else { | ||
492 | + switch(width) { | ||
493 | + | ||
494 | + case WidthValue.WIDE: | ||
495 | + return (_brand == BrandValue.PLUS) ? | ||
496 | + LabelValue.WIDE_PLUS : LabelValue.WIDE; | ||
497 | + | ||
498 | + case WidthValue.STANDARD: | ||
499 | + return LabelValue.STANDARD; | ||
500 | + | ||
501 | + case WidthValue.ICON_ONLY: | ||
502 | + return ''; | ||
503 | + | ||
504 | + default: | ||
505 | + console.warn("bad width value: ", width); | ||
506 | + return LabelValue.STANDARD; | ||
507 | + } | ||
508 | + } | ||
509 | + }, | ||
510 | + | ||
511 | + /** Sign in user. Opens the authorization dialog for signing in. | ||
512 | + * The dialog will be blocked by a popup blocker unless called inside click handler. | ||
513 | + */ | ||
514 | + signIn: function () { | ||
515 | + this.$.aware.signIn(); | ||
516 | + }, | ||
517 | + | ||
518 | + _signInKeyPress: function (e) { | ||
519 | + if (e.which == 13 || e.keyCode == 13 || e.which == 32 || e.keyCode == 32) { | ||
520 | + e.preventDefault(); | ||
521 | + this.signIn(); | ||
522 | + } | ||
523 | + }, | ||
524 | + | ||
525 | + /** Sign out the user */ | ||
526 | + signOut: function () { | ||
527 | + this.fire('google-signout-attempted'); | ||
528 | + this.$.aware.signOut(); | ||
529 | + }, | ||
530 | + | ||
531 | + _signOutKeyPress: function (e) { | ||
532 | + if (e.which == 13 || e.keyCode == 13 || e.which == 32 || e.keyCode == 32) { | ||
533 | + e.preventDefault(); | ||
534 | + this.signOut(); | ||
535 | + } | ||
536 | + } | ||
537 | + }); | ||
538 | + }()); | ||
539 | +</script> |
bower_components/google-signin/index.html
0 → 100644
1 | +<!doctype html> | ||
2 | +<!-- Copyright (c) 2014 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> |
datalets/test-google-components/test.html
0 → 100644
1 | +<!DOCTYPE html> | ||
2 | +<html lang="en"> | ||
3 | +<head> | ||
4 | + <meta charset="UTF-8"> | ||
5 | + <title>Google spreadsheet and document test page</title> | ||
6 | + | ||
7 | + <script type="text/javascript" src="../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script> | ||
8 | + <script type="text/javascript" src="../shared_js/jquery-1.11.2.min.js"></script> | ||
9 | + | ||
10 | + <link rel="import" href="../../bower_components/google-sheets/google-sheets.html"> | ||
11 | + <link rel="import" href="../../bower_components/iron-flex-layout/iron-flex-layout.html"> | ||
12 | + <link rel="import" href="../../bower_components/iron-icons/iron-icons.html"> | ||
13 | + <link rel="import" href="../../bower_components/paper-fab/paper-fab.html"> | ||
14 | + <link rel="import" href="../linechart-datalet/linechart-datalet.html"> | ||
15 | + | ||
16 | + <style> | ||
17 | + #sheet{ | ||
18 | + height: 400px; | ||
19 | + width: 40%; | ||
20 | + margin: 40px; | ||
21 | + } | ||
22 | + | ||
23 | + #showVisualization{ | ||
24 | + background-color: #2196F3; | ||
25 | + color: #ffffff; | ||
26 | + margin-left: 50px; | ||
27 | + } | ||
28 | + | ||
29 | + | ||
30 | + #datalet_placeholder{ | ||
31 | + height: 400px; | ||
32 | + width: 40%; | ||
33 | + margin: 40px;/ | ||
34 | + } | ||
35 | + | ||
36 | + #doc{ | ||
37 | + height: 400px; | ||
38 | + width: 100%; | ||
39 | + } | ||
40 | + </style> | ||
41 | + | ||
42 | + <script> | ||
43 | + | ||
44 | + getData = function() | ||
45 | + { | ||
46 | + var sheet = document.querySelector('google-sheets'); | ||
47 | + | ||
48 | + sheet.addEventListener('google-sheet-data', function(e) | ||
49 | + { | ||
50 | + var data = []; | ||
51 | + //get the keys | ||
52 | + for(var key in this.rows[0]) { | ||
53 | + if (key.match(/gsx\$*/)) { | ||
54 | + data.push({name: key.replace("gsx$", ""), data: []}); | ||
55 | + } | ||
56 | + } | ||
57 | + //fill the structure with values | ||
58 | + for(var row in this.rows){ | ||
59 | + var i = 0; | ||
60 | + for(var key in this.rows[row]){ | ||
61 | + if(key.match(/gsx\$*/)){ | ||
62 | + data[i++].data.push(this.rows[row][key].$t.replace("'","")); | ||
63 | + } | ||
64 | + } | ||
65 | + | ||
66 | + } | ||
67 | + | ||
68 | + $("#datalet_placeholder").html('<linechart-datalet ' + | ||
69 | + 'data-url="https://docs.google.com/spreadsheets/d/1EYJ88pOsbc0GkUTTdPhuReUjHewk1fhis9VZBXes_Ao" ' + | ||
70 | + //'fields=\'[]\'' + | ||
71 | + 'title="Google spreadsheet realtime data visualization"' + | ||
72 | + 'data=\'' + JSON.stringify(data) + '\'>' + | ||
73 | + '</linechart-datalet>'); | ||
74 | + | ||
75 | + $("#spreadsheet_url").html('<a href="' + this.openInGoogleDocsUrl + '" target="_blank">' + this.openInGoogleDocsUrl + '</a>'); | ||
76 | + | ||
77 | + }); | ||
78 | + | ||
79 | + sheet.addEventListener('error', function(e) { | ||
80 | + // e.detail.response | ||
81 | + }); | ||
82 | + | ||
83 | + } | ||
84 | + | ||
85 | + refresh = function(){ | ||
86 | + $("#sheet-component").html('<google-sheets key="1EYJ88pOsbc0GkUTTdPhuReUjHewk1fhis9VZBXes_Ao" published></google-sheets>'); | ||
87 | + getData(); | ||
88 | + } | ||
89 | + | ||
90 | + $( document ).ready(function() { | ||
91 | + getData(); | ||
92 | + }); | ||
93 | + | ||
94 | + </script> | ||
95 | + | ||
96 | +</head> | ||
97 | +<body is="dom-bind"> | ||
98 | + <div class="layout vertical"> | ||
99 | + <div class="layout vertical"> | ||
100 | + <div class="layout horizontal" style="width: 100%;"> | ||
101 | + <h1>Google Spreadsheet realtime visualization with Datalet</h1> | ||
102 | + <paper-fab id="showVisualization" icon="refresh" onClick="refresh()"></paper-fab> | ||
103 | + </div> | ||
104 | + <div class="layout horizontal" style="width: 100%;"> | ||
105 | + <h3 id="spreadsheet_url"></h3> | ||
106 | + </div> | ||
107 | + <div class="layout horizontal"> | ||
108 | + <iframe id="sheet" src="https://docs.google.com/spreadsheets/d/1EYJ88pOsbc0GkUTTdPhuReUjHewk1fhis9VZBXes_Ao/edit?usp=sharing?embedded=true"></iframe> | ||
109 | + <div id="datalet_placeholder"></div> | ||
110 | + </div> | ||
111 | + </div> | ||
112 | + | ||
113 | + <div class="layout vertical"> | ||
114 | + <h1 style="width: 100%;margin-top: 100px;">Google Docs realtime visualization with Datalet</h1> | ||
115 | + <iframe id="doc" src="https://docs.google.com/document/d/1IIfmqTGBpTkEMHPnuxJeoOJI3u-8wQu9dkf49X2T6SE/edit?usp=sharing?embedded=true"></iframe> | ||
116 | + </div> | ||
117 | + </div> | ||
118 | + | ||
119 | + <div id="sheet-component"> | ||
120 | + <google-sheets key="1EYJ88pOsbc0GkUTTdPhuReUjHewk1fhis9VZBXes_Ao" published></google-sheets> | ||
121 | + </div> | ||
122 | + | ||
123 | +</body> | ||
124 | +</html> | ||
0 | \ No newline at end of file | 125 | \ No newline at end of file |