Google picker popup blocker

I have a mobile site that lists tasks, the user applies and uploads his resume (resume). I want them to be able to select a file from their Google Drive.

I created an Hello Hello example here - https://developers.google.com/picker/docs/ (code is reproduced here for convenience)

The problem is that if you are not already logged in to Drive, a pop-up window will open to enter the system. This is bad on the desktop, but very bad on the phone.

I tried this solution but get 'TypeError: gapi.auth is undefined'

I also tried to run the collector from the onclick event, and not onload, as described in the docs.

function launchDrive() { gapi.load('auth', {'callback': onAuthApiLoad}); gapi.load('picker', {'callback': onPickerApiLoad}); } <input type='button' value='Launch Drive' onclick='launchDrive();'> 

Google code example:

 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <title>Google Picker Example</title> <script type="text/javascript"> var developerKey = 'xxxxxxxYYYYYYYY-12345678'; var clientId = "1234567890-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com" var scope = ['https://www.googleapis.com/auth/photos']; var pickerApiLoaded = false; var oauthToken; function onApiLoad() { gapi.load('auth', {'callback': onAuthApiLoad}); gapi.load('picker', {'callback': onPickerApiLoad}); } function onAuthApiLoad() { window.gapi.auth.authorize( { 'client_id': clientId, 'scope': scope, 'immediate': false }, handleAuthResult); } function onPickerApiLoad() { pickerApiLoaded = true; createPicker(); } function handleAuthResult(authResult) { if (authResult && !authResult.error) { oauthToken = authResult.access_token; createPicker(); } } // Create and render a Picker object for picking user Photos. function createPicker() { if (pickerApiLoaded && oauthToken) { var picker = new google.picker.PickerBuilder(). addView(google.picker.ViewId.PHOTOS). setOAuthToken(oauthToken). setDeveloperKey(developerKey). setCallback(pickerCallback). build(); picker.setVisible(true); } } // A simple callback implementation. function pickerCallback(data) { var url = 'nothing'; if (data[google.picker.Response.ACTION] == google.picker.Action.PICKED) { var doc = data[google.picker.Response.DOCUMENTS][0]; url = doc[google.picker.Document.URL]; } var message = 'You picked: ' + url; document.getElementById('result').innerHTML = message; } </script> </head> <body> <div id="result"></div> <!-- The Google API Loader script. --> <script type="text/javascript" src="https://apis.google.com/js/api.js?onload=onApiLoad"></script> </body> </html> 

May 13, 2015

Further, to answer Jason, here is what I also tried (called by the oncllick button):

 function launchDrive() { //gapi.load('auth', {'callback': onAuthApiLoad}); gapi.auth.init(onAuthApiLoad); gapi.load('picker', {'callback': onPickerApiLoad}); } 
+6
source share
4 answers

You want to call gapi.auth.init. See Docs here: https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiauthinit

Initializes the authorization function. Call this when the client boots up to prevent pop-ups from blocking the auth window when gapi.auth.authorize is called.

+2
source

Now i'm working.

In the example for the collector https://developers.google.com/picker/docs/, it calls:

  <script type="text/javascript" src="https://apis.google.com/js/api.js?onload=onApiLoad"></script> 

In this example https://developers.google.com/api-client-library/javascript/start/start-js it calls:

 <script src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script> 

Using client.js fixes the "TypeError: gapi.auth is undefined" problem and thus the login popup window works.

Perhaps api.js is an older version of the API?

+1
source

To solve your problem you need to understand how google does oauth in your case:

  • gapi performs init actions.
  • gapi opens the google auth page in a new popup and you are logged into it
  • After the login is successful, gapi receives a notification and you receive your token.

Why does the browser block the popup in the second step:

  • the original event is no longer in the window ( window.event destroyed).
  • User manually blocked popup from current site

So, if the user has not blocked the popup, and the popup is still blocked, the actions in the yoke look something like this:

 <input type="button" onclick="auth" value="click"/> function auth() { setTimeout(function() { // by this time window.event is destroyed, that why browser blocks the popup window.open(document.URL, '_blank', 'location=yes,height=570,width=520,scrollbars=yes,status=yes'); }, 100) } 

So what you should do:

  • Make sure that after clicking the button you are not performing asynchronous actions such as XHRequests or others
  • Make sure gapi is on and ready by the time users click the button, so by the time gapi needs to create a popup, window.event will not be NULL. Therefore, move all initi methods for the lang to DOMContentLoaded .
  • As another option, you can use the oauth stream on the server side, which means that instead of popup, the user will be redirected to the gauth page on the current tab.
0
source

Just go to the bottom

Here is the code that is currently working for me. This is my first hour using this API, although I really don't know what any of these functions do, and I don't know what the correct order and error handling is, but at least now it works. Perhaps this will help someone else in the future.

 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <title>Google Picker Example</title> </head> <body style="width: 70%; margin: 100px auto;"> <!-- Added a button to open picker --> <button onclick="loadPicker();" >Open from GoogleDrive</button> <div id="result"></div> <!-- Moved to end of body tag instead of head --> <script type="text/javascript"> // The Browser API key obtained from the Google API Console. // Replace with your own Browser API key, or your own key. var developerKey = '<IDK WHAT SUPPOSED TO GO HERE, BUT ITS OK>'; // The Client ID obtained from the Google API Console. Replace with your own Client ID. var clientId = "<YOUR CLIENT ID GOES HERE>.apps.googleusercontent.com" // Replace with your own project number from console.developers.google.com. // See "Project number" under "IAM & Admin" > "Settings" var appId = "<YOUR APP ID GOES HERE>"; // Scope to use to access user Drive items. var scope = ['https://www.googleapis.com/auth/drive']; var pickerApiLoaded = false; var oauthToken; // Use the Google API Loader script to load the google.picker script. function loadPicker() { // This needs to be client:auth2 no client gapi.load('client:auth2', {'callback': onAuthApiLoad}); gapi.load('picker', {'callback': onPickerApiLoad}); } function onAuthApiLoad() { // we need to init gapi.client with the clientId and scope first gapi.client.init({ clientId: clientId, scope: scope }); // Now we can authorize? seems like the same thing here window.gapi.auth.authorize( { 'client_id': clientId, 'scope': scope, 'immediate': false }, handleAuthResult); } function onPickerApiLoad() { pickerApiLoaded = true; createPicker(); } function handleAuthResult(authResult) { if (authResult && !authResult.error) { oauthToken = authResult.access_token; createPicker(); } } // Create and render a Picker object for searching images. function createPicker() { // Wow this is a mess if (pickerApiLoaded && oauthToken) { var view = new google.picker.View(google.picker.ViewId.DOCS); view.setMimeTypes("image/png,image/jpeg,image/jpg"); var picker = new google.picker.PickerBuilder() .enableFeature(google.picker.Feature.NAV_HIDDEN) .enableFeature(google.picker.Feature.MULTISELECT_ENABLED) .setAppId(appId) .setOAuthToken(oauthToken) .addView(view) .addView(new google.picker.DocsUploadView()) // Guess this is... optional? //.setDeveloperKey(developerKey) .setCallback(pickerCallback) .build(); picker.setVisible(true); } } // A simple callback implementation. function pickerCallback(data) { if (data.action == google.picker.Action.PICKED) { var fileId = data.docs[0].id; alert('Selected fileId: ' + fileId); } } </script> <!-- The Google API Loader script. Removed the autorun --> <script type="text/javascript" src="https://apis.google.com/js/api.js"></script> </body> </html> 

Edit: if you get a popup that doesn't load, just close it and click the button again. This fixed another issue I just had.

Again, I donโ€™t know what I'm doing, so I hope I can better understand this and clarify the situation later.

E2: Oh, there is more information about OAuth2 on the Javascript GAPI documentation page, which can be found here: https://developers.google.com/api-client-library/javascript/features/authentication

From another document, it seems that gapi.load('client', callback) will load auth2 if it is not already loaded. Calling gapi.load('client:auth2', callback) simply save 1 network request.

Note. When authorizing the application using Oauth 2.0, you also do not need to set the API key, as in the first example. However, it is good practice if your code is ever extended to handle unauthorized requests.

This explains why I can remove the API / developer key.

Edit 3: It is good that the above code is technically incorrect.

Warning: do not use this method along with recommended costs gapi.auth2.init and signIn. These are two different behaviors (authorization for gapi.auth2.authorize vs Authentication for gapi.auth2.init / signIn) and will have unexpected problems if they are used in the same application.

autorize - for single-user authentication (if you have been registered with two Google accounts, for example). Although the use of gapi.init() intended for a longer session (for example, to log in and out of a website).

How it works now, I donโ€™t know.


Do not use the above code, just want to document the progress. Here's a better demo with getAuthResponse()

 <html> <head></head> <body> <div style="padding: 50px"> <h2 style="color: #2196f3;">Status: <span id='status'></span></h2> <button id="signin-button" onclick="handleSignInClick()">Sign In</button> <button id="signout-button" onclick="handleSignOutClick()">Sign Out</button> <button id="signout-button" onclick="openFile()">Open File</button> </div> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <script type="text/javascript"> var cid = '<CLIENTID_HERE>'; var scope = 'https://www.googleapis.com/auth/drive'; var authenticated = false; var pickerLoaded = false; var auth = null; var user = null; var response = null; var token = null; var stat = $('#status'); function openFile() { gapi.load('client:auth2', initClient); gapi.load('picker', onPickerLoad); } function initClient() { stat.html("starting"); gapi.client.init({ clientId: cid, scope: scope }).then( function () { console.log("init"); // Check if we are logged in. auth = gapi.auth2.getAuthInstance(); auth.isSignedIn.listen(onStatusChange); authenticated = auth.isSignedIn.get(); stat.html(authenticated); if (authenticated) { stat.html("Logged In!"); user = auth.currentUser.get(); response = user.getAuthResponse(true); token = response.access_token; showPicker(); } else { stat.html("Logged Out!"); } }, function(){stat.html("error")}); } function onStatusChange(isSignedIn) { if (isSignedIn) { stat.html("Logged In!"); authenticated = true; user = auth.currentUser.get(); response = user.getAuthResponse(true); token = response.access_token; showPicker(); showPicker(); } else { authenticated = false; stat.html("Logged Out!"); } } function handleSignInClick(event) { gapi.auth2.getAuthInstance().signIn(); } function handleSignOutClick(event) { gapi.auth2.getAuthInstance().signOut(); alert("signed out"); } function onPickerLoad() { pickerLoaded = true; showPicker(); } function showPicker() { if (pickerLoaded && authenticated) { var view = new google.picker.View(google.picker.ViewId.DOCS); var picker = new google.picker.PickerBuilder(); picker.addView(view); picker.enableFeature(google.picker.Feature.MULTISELECT_ENABLED); picker.setOAuthToken(token); picker.setAppId() picker.setCallback(onDriveFileOpen); picker = picker.build(); picker.setVisible(true); } } function onDriveFileOpen(data) { console.log(data); if (data.action == google.picker.Action.PICKED) { var fileId = data.docs[0].id; console.log(fileId); alert(data.docs[0].name); } } </script> <script async defer src="https://apis.google.com/js/api.js"> </script> </body> </html> 
-1
source

Source: https://habr.com/ru/post/986825/


All Articles