Last active
April 16, 2017 22:10
-
-
Save Scarygami/7752c01b08a1c883e679 to your computer and use it in GitHub Desktop.
Polymer Google Sign-in
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes"> | |
<title>google-signin Demo</title> | |
<script src="platform/platform.js"></script> | |
<link rel="import" href="google-signin/google-signin.html"> | |
<link rel="import" href="google-calendar/google-calendar.html"> | |
<!-- Demo only styles --> | |
<style> | |
@import url(http://fonts.googleapis.com/css?family=Roboto:400,100,100italic,300,300italic,400italic,500,700,500italic,900,700italic,900italic); | |
* { font-family: 'Roboto', sans-serif; line-height:1.2; vertical-align:middle; } | |
body { | |
background: rgba(204, 204, 204, 0.31); | |
} | |
.card { | |
min-width: 300px; | |
max-width: 400px; | |
padding:1.5rem; | |
box-shadow:0 1px 2px #aaa; | |
background:white; | |
margin:1rem 1rem 1rem; | |
border-radius:3px; | |
user-select:none; | |
transform-origin:top left; | |
position:relative; | |
z-index:2; | |
} | |
.card:nth-child(even){ | |
transform-origin:top right; | |
} | |
.map { | |
background: whitesmoke; | |
margin: .5rem -1.5rem 0 -1.5rem; | |
padding: 0.5rem; | |
} | |
h1 { | |
font-size:2rem; | |
font-weight:200; | |
} | |
h1 strong { | |
font-weight:300; | |
color:#539D00; | |
} | |
h2 { | |
font-size:.9rem; | |
line-height:2.5; | |
color:gray; | |
font-weight:400; | |
} | |
</style> | |
</head> | |
<body unresolved> | |
<p>A `google-signin` looks like this:</p> | |
<div id="status"></div> | |
<google-signin clientId="651124942659.apps.googleusercontent.com" scopes="profile"></google-signin> | |
<!-- Just for demonstration purposes --> | |
<template id="profile" bind="{{ profile }}"> | |
<div class="card"> | |
<h1><strong>{{displayName}}</strong></h1> | |
<h2>Is currently signed-in</h2> | |
<div class="map"> | |
<p> | |
<strong>Gender</strong> {{gender}} | |
</p> | |
<p> | |
<strong>Skills</strong> {{skills}} | |
</p> | |
<p> | |
<strong>Avatar</strong> | |
<p> | |
<img src="{{image.url}}" /> | |
</p> | |
</p> | |
<p> | |
<strong>G+ URL</strong> <a href="{{url}}">{{url}}</a> | |
</p> | |
</div> | |
</div> | |
</template> | |
<google-calendar-list title="Calendar Test"></google-calendar-list> | |
<script> | |
document.addEventListener("google-signin-success", function(e) { | |
// Access the GAPI instance passed back from authorization | |
var gapi = e.detail.gapi; | |
// Load V1 of the G+ API | |
gapi.client.load('plus', 'v1', function() { | |
// To retreive profile information for a user, use the | |
// people.get API method. For profile info for the currently | |
// authorized user, use the userId value of me. | |
var request = gapi.client.plus.people.get({ | |
'userId': 'me' | |
}); | |
request.execute(function(resp) { | |
// Some useful profile info is now available via | |
// resp.displayName, resp.skills etc | |
// We can render this info in a template | |
console.log(resp); | |
var t = document.querySelector("#profile"); | |
t.model = {}; | |
t.model.profile = resp; | |
}); | |
}); | |
document.querySelector("#status").innerHTML = "You are now signed in."; | |
}); | |
document.addEventListener("google-signed-out", function() { | |
document.querySelector("#status").innerHTML = "You are now signed out."; | |
}); | |
document.addEventListener("google-signout-attempted", function() { | |
document.querySelector("#status").innerHTML = "You attempted to sign out."; | |
}); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link rel="import" href="../polymer/polymer.html"> | |
<link rel="import" href="../google-signin-aware/google-signin-aware.html"> | |
<link rel="import" href="../google-apis/google-apis.html"> | |
<!-- | |
Element loading Google Calendar API. | |
##### Example | |
<google-calendar-api id="calendar"></google-calendar-api> | |
<script> | |
window.addEventListener('api-load', function() { | |
var request = document.getElementById('calendar').api.calendarList.list(); | |
request.execute(function(resp) { | |
console.log(resp); | |
}); | |
}); | |
</script> | |
@element google-calendar-api | |
@blurb Element loading Google Calendar API. | |
@status alpha | |
@url http://googlewebcomponents.github.io/google-calendar | |
--> | |
<polymer-element name="google-calendar-api" | |
attributes="version" | |
extends="google-client-api" | |
on-client-api-load="{{loadCalendarApi}}"> | |
<script> | |
(function() { | |
var loader = null; | |
Polymer('google-calendar-api', { | |
/** | |
* Called when the Calendar API is loaded. | |
* @event api-load | |
*/ | |
/** | |
* Version of the API to load, e.g. 'v3'. | |
* @attribute version | |
* @type string | |
*/ | |
version: 'v3', | |
/** | |
* Returns the loaded Calendar API. | |
* @method api | |
*/ | |
get api() { | |
return (window.gapi && window.gapi.client) ? window.gapi.client.calendar : undefined; | |
}, | |
notify: function() { | |
this.fire('client-api-load', arguments); | |
}, | |
loadCalendarApi: function(e) { | |
if (gapi.client.calendar) { | |
this.fire(this.notifyEvent, e.detail); | |
} else if (loader) { | |
loader.addEventListener(loader.notifyEvent, function() { | |
this.fire(this.notifyEvent, e.detail); | |
}.bind(this)); | |
} else { | |
loader = this; | |
gapi.client.load('calendar', this.version, | |
this.fire.bind(this, this.notifyEvent, e.detail) | |
); | |
} | |
} | |
}); | |
})(); | |
</script> | |
</polymer-element> | |
<!-- | |
Element providing a list of Google Calendars for a signed in user. | |
##### Example | |
<google-calendar-list title="What I'm up to"></google-calendar-list> | |
@element google-calendar-list | |
@blurb Element providing a list of Google Calendars for a signed in user. | |
@status alpha | |
@url http://googlewebcomponents.github.io/google-calendar | |
--> | |
<polymer-element name="google-calendar-list"> | |
<template> | |
<style> | |
:host, span { | |
display: inline-block; | |
} | |
ul { | |
list-style: none; | |
padding: 0; | |
} | |
li { | |
font-family: Arial, sans-serif; | |
display: block; | |
list-style: none; | |
width: 300px; | |
border-radius: .2em; | |
padding: .2em; | |
margin: .2em; | |
overflow: hidden; | |
} | |
li a { | |
color: inherit; | |
display: block; | |
text-decoration: none; | |
} | |
google-signin { | |
float: right; | |
} | |
</style> | |
<google-calendar-api id="calendar" on-api-load="{{displayCalendars}}"></google-calendar-api> | |
<google-signin-aware | |
scopes="https://www.googleapis.com/auth/calendar.readonly" | |
on-google-signin-aware-success="{{signIn}}"></google-signin-aware> | |
<ul id="calendars"> | |
<li> | |
{{title || 'My calendars'}} | |
</li> | |
<template repeat="{{c in calendars}}"> | |
<li style="background-color: {{c.backgroundColor}}"> | |
<a href="https://www.google.com/calendar/embed?src={{c.id}}&ctz={{c.timeZone}}" target="_blank"> | |
{{c.summary}} | |
</a> | |
</li> | |
</template> | |
</ul> | |
</template> | |
<script> | |
Polymer('google-calendar-list', { | |
apikey: null, | |
signedIn: false, | |
/** | |
* A title to be displayed on top of the calendar list. | |
* @attribute title | |
* @type string | |
*/ | |
title: 'My calendars', | |
signIn: function() { | |
this.signedIn = true; | |
this.displayCalendars(); | |
}, | |
/** | |
* Displays the calendar list if the user is signed in to Google. | |
* | |
* @method displayCalendars | |
*/ | |
displayCalendars: function() { | |
if (this.signedIn && this.$.calendar.api) { | |
var request = this.$.calendar.api.calendarList.list(); | |
request.execute(function(resp) { | |
this.calendars = resp.items; | |
}.bind(this)); | |
} | |
} | |
}); | |
</script> | |
</polymer-element> | |
<!-- | |
A badge showing the free/busy status based on the events in a given calendar. | |
##### Example | |
<google-calendar-busy-now | |
calendarId="YOUR_CAL_ID" | |
apiKey="YOUR_API_KEY" | |
busyLabel="Do not disturb" | |
freeLabel="I'm free, talk to me!"> | |
</google-calendar-busy-now> | |
@element google-calendar-busy-now | |
@blurb A badge showing the free/busy status based on the events in a given calendar. | |
@status alpha | |
@url googlewebcomponent.github.io/google-calendar | |
--> | |
<polymer-element name="google-calendar-busy-now" | |
attributes="calendarId busyLabel freeLabel apiKey"> | |
<template> | |
<style no-shim> | |
span { | |
font-family: Arial, sans-serif; | |
display: inline-block; | |
border-radius: .2em; | |
padding: .2em; | |
margin: .2em; | |
overflow: hidden; | |
} | |
.busy { | |
background-color: #FA573C; | |
} | |
.free { | |
background-color: #7BD148; | |
} | |
.na { | |
background-color: #999; | |
} | |
</style> | |
<google-calendar-api xid="2" id="calendar" on-api-load="{{displayBusy}}"></google-calendar-api> | |
<span class="{{className}}">{{label}}</span> | |
</template> | |
<script> | |
(function() { | |
var MS_PER_MINUTE = 60000; | |
var TIME_SPAN = 30; | |
Polymer('google-calendar-busy-now', { | |
/** | |
* Event from this calendar decide whether the status is free/busy. | |
* @attribute calendarId | |
* @type string | |
*/ | |
calendarId: null, | |
/** | |
* API key to use with Calendar API requests. | |
* @attribute apiKey | |
* @type string | |
*/ | |
apiKey: null, | |
/** | |
* Label to be displayed if the status is busy. | |
* @attribute busyLabel | |
* @type string | |
*/ | |
busyLabel: 'I\'m busy', | |
/** | |
* Label to be displayed if the status is free. | |
* @attribute freeLabel | |
* @type string | |
*/ | |
freeLabel: 'I\'m free', | |
className: '', | |
label: '', | |
calendarIdChanged: function() { | |
this.displayBusy(); | |
}, | |
/** | |
* Displays the busy/free status. | |
* @method displayBusy | |
*/ | |
displayBusy: function() { | |
if (!this.calendarId) { | |
console.log('CalendarId is required for this component'); | |
return; | |
} | |
if (this.$.calendar.api) { | |
if (this.apiKey) { | |
gapi.client.setApiKey(this.apiKey); | |
} | |
var now = new Date(); | |
var query = { | |
timeMin: now.toISOString(), | |
timeMax: new Date(now.valueOf() + | |
TIME_SPAN * MS_PER_MINUTE).toISOString(), | |
items: [ | |
{ | |
id: this.calendarId | |
} | |
] | |
} | |
var request = this.$.calendar.api.freebusy.query(query); | |
request.execute(function(resp) { | |
if (!resp.calendars) { | |
this.label = this.freeLabel; | |
this.className = 'free'; | |
return; | |
} | |
if (resp.calendars[this.calendarId].errors) { | |
this.label = 'n/a'; | |
this.className = 'na' | |
return; | |
} | |
var now = new Date(); | |
var busyTimes = resp.calendars[this.calendarId]; | |
for (var i = 0, busyTime; busyTime = busyTimes.busy[i]; i++) { | |
var start = new Date(busyTime.start); | |
var end = new Date(busyTime.end); | |
var busy = start < now && now < end; | |
this.label = busy ? this.busyLabel : this.freeLabel; | |
this.className = busy ? 'busy' : 'free'; | |
if (busy) { | |
break; | |
} | |
} | |
}.bind(this)); | |
} | |
} | |
}); | |
})(); | |
</script> | |
</polymer-element> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link rel="import" href="../polymer/polymer.html"> | |
<link rel="import" href="../polymer-signals/polymer-signals.html"> | |
<polymer-element name="google-signin-aware" attributes="scopes"> | |
<template> | |
<polymer-signals on-polymer-signal-google-auth-success="{{authSuccess}}"></polymer-signals> | |
</template> | |
<script> | |
(function() { | |
var loader = null; | |
Polymer('google-signin-aware', { | |
scopes: '', | |
attached: function() { | |
this.fire('polymer-signal', { | |
name: 'google-auth-request', | |
data: this.scopes | |
}); | |
}, | |
authSuccess: function (e, detail, sender) { | |
// Check if correct scopes authorized, if not we will have to wait | |
var complete = false; | |
if (detail && detail.scopes) { | |
var scopes = this.scopes.split(' '); | |
complete = true; | |
for (var i = 0; i < scopes.length; i++) { | |
if (scopes[i] !== '' && !detail.scopes[scopes[i].toLowerCase()]) { | |
complete = false; | |
break; | |
} | |
} | |
} | |
if (complete) { | |
this.fire('google-signin-aware-success'); | |
} | |
} | |
}); | |
})(); | |
</script> | |
</polymer-element> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link rel="import" href="../polymer/polymer.html"> | |
<link rel="import" href="../google-apis/google-apis.html"> | |
<link rel="import" href="../polymer-signals/polymer-signals.html"> | |
<!-- | |
Copyright (c) 2014 Google Inc. All rights reserved. | |
LICENSE: github.com/GoogleWebComponents/google-signin/blob/master/LICENSE | |
AUTHOR(s): Addy Osmani and Rob Dodson. | |
---> | |
<!-- | |
google-signin is used to authenticate with Google, allowing you to interact with other Google | |
APIs such as Drive and Google+. | |
The attribute `clientId` is provided in your Google Developers Console (https://console.developers.google.com). The `scopes` attribute allows | |
you to specify which scope permissions are required (e.g do you want to allow interaction with the Google Drive API). The `requestVisibleActions` attribute is necessary if you want to write app activities | |
(https://developers.google.com/+/web/app-activities/) on behalf of the user. Please note that this | |
attribute is only valid in combination with the plus.login scope (https://www.googleapis.com/auth/plus.login). | |
The `labelSignin` attribute is an optional piece of text used for customizing the label on the sign-in button. `labelSignout` allows you to customize the label for sign-out. The `google-signin-success` event is triggered when a user successfully authenticates and `google-signin-failure` is triggered when this is not the case. Both events will also provide the data returned by the Google client authentication process. | |
Additional events, such as `google-signout-attempted` and `google-signed-out` are triggered when the user | |
attempts to sign-out and successfully signs out. | |
##### Example | |
<google-signin cliendId="..." scopes="https://www.googleapis.com/auth/drive"></google-signin> | |
<google-signin labelSignin="Sign-in" cliendId="..." scopes="https://www.googleapis.com/auth/drive"></google-signin> | |
@class google-signin | |
@blurb A Polymer element for authenticating and authorizing with Google Services. | |
@status alpha | |
@homepage http://googlewebcomponents.github.io/google-signin | |
--> | |
<polymer-element name="google-signin" attributes="clientId scopes cookiePolicy requestVisibleActions labelSignin labelSignout labelAdditional"> | |
<template> | |
<style> | |
:host { | |
display: inline-block; | |
} | |
</style> | |
<google-client-api></google-client-api> | |
<polymer-signals on-polymer-signal-google-auth-request="{{authRequest}}"></polymer-signals> | |
<template if="{{ !signedIn }}"> | |
<input type="button" value="{{labelSignin}}" on-click="{{ signIn }}" /> | |
</template> | |
<template if="{{ signedIn && !additionalAuth }}"> | |
<input type="button" value="{{labelSignout}}" on-click="{{ signOut }}" /> | |
</template> | |
<template if="{{ signedIn && additionalAuth }}"> | |
<input type="button" value="{{labelAdditional}}" on-click="{{ signIn }}" /> | |
</template> | |
</template> | |
<script> | |
(function() { | |
var CLIENT_ID = ''; | |
var SCOPES = []; | |
var REQUEST_VISIBLE_ACTIONS = ''; | |
var COOKIE_POLICY = ''; | |
var handler; | |
var authorized_scopes = {}; | |
/** | |
* Checks whether authorized and requested scopes match and | |
* displays button for additional auth if necessary | |
*/ | |
function checkScopes() { | |
handler.additionalAuth = false; | |
for (var i = 0; i < SCOPES.length; i++) { | |
if (SCOPES[i] !== '') { | |
if (!authorized_scopes[SCOPES[i].toLowerCase()]) { | |
handler.additionalAuth = true; | |
break; | |
} | |
} | |
} | |
} | |
/** | |
* Called when authorization server replies. | |
* | |
* @param {Object} authResult Authorization result. | |
* @event google-signin-success | |
*/ | |
function handleAuthResult(authResult) { | |
if (authResult && !authResult.error) { | |
// Access token has been successfully retrieved | |
// Store authorized scopes to check against for new requests | |
authorized_scopes = {} | |
var tmp_scopes = authResult.scope.split(' '); | |
for (var i = 0; i < tmp_scopes.length; i++) { | |
if (tmp_scopes[i] !== "") { | |
authorized_scopes[tmp_scopes[i].toLowerCase()] = true; | |
if (tmp_scopes[i] === 'https://www.googleapis.com/auth/userinfo.profile') { | |
authorized_scopes['profile'] = true; | |
} | |
if (tmp_scopes[i] === 'https://www.googleapis.com/auth/userinfo.email') { | |
authorized_scopes['email'] = true; | |
} | |
} | |
} | |
// Trigger the google-signin-success event | |
handler.fire('polymer-signal', { | |
name: 'google-auth-success', | |
data: {result: authResult, scopes: authorized_scopes} | |
}); | |
handler.fire('google-signin-success', {result: authResult, gapi: gapi}); | |
handler.signedIn = true; | |
checkScopes(); | |
} else { | |
if (authResult && authResult.error == "user_signed_out") { | |
// Fire event to indicate user signed out | |
handler.fire('google-signed-out', {result: authResult}); | |
} else { | |
// Fire event to indicate sign-in was not successful | |
handler.fire('google-signin-failure', {result: authResult}); | |
} | |
authorized_scopes = {}; | |
// No access token could be retrieved, show the button to start the authorization flow. | |
handler.signedIn = false; | |
} | |
handler.flowComplete = true; | |
} | |
Polymer('google-signin', { | |
/** | |
* a Google Developers clientId reference | |
* | |
* @attribute clientId | |
* @type string | |
*/ | |
clientId: '', | |
/** | |
* The scopes to provide access to (e.g https://www.googleapis.com/auth/drive) and should be space-delimited. | |
* | |
* @attribute scopes | |
* @type string | |
* @default 'profile' | |
*/ | |
scopes: 'profile', | |
/** | |
* The cookie policy defines what URIs have access to the session cookie | |
* remembering the user's sign-in state. | |
* See https://developers.google.com/+/web/signin/reference#determining_a_value_for_cookie_policy | |
* | |
* @attribute cookiePolicy | |
* @type string | |
* @default 'single_host_origin' | |
*/ | |
cookiePolicy: 'single_host_origin', | |
/** | |
* The app activity types you want to write on behalf of the user | |
* (e.g http://schemas.google.com/AddActivity) | |
* | |
* @attribute requestVisibleActions | |
* @type string | |
*/ | |
requestVisibleActions: '', | |
/** | |
* An optional label for the sign-in button | |
* | |
* @attribute labelSignin | |
* @type string | |
* @default 'Authorize' | |
*/ | |
labelSignin: 'Authorize', | |
/** | |
* An optional label for the sign-out button | |
* | |
* @attribute labelSignout | |
* @type string | |
* @default 'Sign out' | |
*/ | |
labelSignout: 'Sign out', | |
labelAdditional: 'Additional permissions required', | |
signedIn: false, | |
additionalAuth: false, | |
flowComplete: false, | |
attached: function() { | |
if (this.clientId === '') { | |
throw "A valid clientId is required to use this element"; | |
} | |
CLIENT_ID = this.clientId; | |
SCOPES = this.scopes.split(' '); | |
COOKIE_POLICY = this.cookiePolicy; | |
REQUEST_VISIBLE_ACTIONS = this.requestVisibleActions; | |
handler = this; | |
// For page-level configuration the callback has to be in global namespace | |
window.handleAuthResult = handleAuthResult; | |
var meta = document.createElement('meta'); | |
meta.setAttribute('name', 'google-signin-clientid'); | |
meta.setAttribute('content', CLIENT_ID); | |
document.head.appendChild(meta); | |
meta = document.createElement('meta'); | |
meta.setAttribute('name', 'google-signin-scope'); | |
meta.setAttribute('content', SCOPES.join(' ')); | |
document.head.appendChild(meta); | |
meta = document.createElement('meta'); | |
meta.setAttribute('name', 'google-signin-cookiepolicy'); | |
meta.setAttribute('content', COOKIE_POLICY); | |
document.head.appendChild(meta); | |
meta = document.createElement('meta'); | |
meta.setAttribute('name', 'google-signin-callback'); | |
meta.setAttribute('content', 'handleAuthResult'); | |
document.head.appendChild(meta); | |
if (REQUEST_VISIBLE_ACTIONS) { | |
meta = document.createElement('meta'); | |
meta.setAttribute('name', 'google-signin-requestvisibleactions'); | |
meta.setAttribute('content', REQUEST_VISIBLE_ACTIONS); | |
document.head.appendChild(meta); | |
} | |
}, | |
authRequest: function (e, detail, sender) { | |
var i, new_scopes, extra_scopes; | |
if (detail) { | |
extra_scopes = false; | |
new_scopes = detail.split(" "); | |
for (i = 0; i < new_scopes.length; i++) { | |
if (new_scopes[i] !== "") { | |
if (!authorized_scopes[new_scopes[i].toLowerCase]) { | |
extra_scopes = true; | |
if (SCOPES.indexOf(new_scopes[i]) < 0) { | |
SCOPES.push(new_scopes[i]); | |
} | |
} | |
} | |
} | |
} | |
if (extra_scopes) { | |
if (handler.flowComplete) { | |
handler.additionalAuth = true; | |
} | |
} else { | |
handler.fire('polymer-signal', { | |
name: 'google-auth-success', | |
data: {result: gapi.auth.getToken(), scopes: authorized_scopes} | |
}); | |
} | |
}, | |
signIn: function () { | |
handler.flowComplete = false; | |
gapi.auth.signIn({'scope': SCOPES.join(' ')}); | |
}, | |
signOut: function () { | |
handler.flowComplete = false; | |
handler.fire('google-signout-attempted'); | |
gapi.auth.signOut(); | |
} | |
}); | |
})(); | |
</script> | |
</polymer-element> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment