Turned out to be a few relatively simple bugs, but together they caused enough of a hiccup that I was left scratching my head for a bit. So if anyone else out there finds themselves in the same boat, hopefully these tips will help.

I was interested in checking out Evernote’s API and decided to start with their Javascript tutorial. It turns out that they left out a few things in their writeup:

  • In the original gist of index.html that’s in the tutorial, there’s a missing bracket (‘>‘):
    <input type="submit" value="Login" onClick="app.loginWithEvernote()"</input>

    should be

    <input type="submit" value="Login" onClick="app.loginWithEvernote()"></input>

    If you’re not seeing a button show up on the startup screen, that this could be why.

  • In the original gist of app.success that’s in the tutorial, lines 62-68 are incorrect. There’s an extra ‘}‘ on line 64. If you see an error message like Err: Expecting ")" or something like that, then this might be what’s causing it.
  • In the original gist of app.success that’s in the tutorial, it shows an if loop inside the loadstart eventlistener that spans lines 25-36. In actuality, there are some extra ‘}‘ on lines 34 & 35 and there’s a couple of missing ‘}‘ later on too. When you make the necessary changes, the if loop inside the loadstart eventlistener should actually include lines 25-48. If you see error messages like Err: Cannot read property '0' of undefined, then this might be what’s causing it. With the original (buggy) version, the else if part was outside of the for loop, which is where var y was defined. Thus when you try to call y[0], the y variable is out of scope and you get that error message.

To make it easier for folks, I’m including a gist of app.success. I forked it off of Evernote’s buggy gists, so you can compare the two, if you like:

    success: function(data) {
        var isCallBackConfirmed = false;
        var token = '';
        var vars = data.text.split("&");
        for (var i = 0; i < vars.length; i++) {
            var y = vars[i].split('=');
            if(y[0] === 'oauth_token')  {
                token = y[1];
            }
            else if(y[0] === 'oauth_token_secret') {
                this.oauth_token_secret = y[1];
                localStorage.setItem("oauth_token_secret", y[1]);
            }
            else if(y[0] === 'oauth_callback_confirmed') {
                isCallBackConfirmed = true;
            }
        }
        var ref;
        if(isCallBackConfirmed) {
            // step 2
            ref = window.open(app.evernoteHostName + '/OAuth.action?oauth_token=' + token, '_blank');
            ref.addEventListener('loadstart',
                function(event) {
                    var loc = event.url;
                    if (loc.indexOf(app.evernoteHostName + '/Home.action?gotOAuth.html?') >= 0) {
                        var index, verifier = '';
                        var got_oauth = '';
                        var params = loc.substr(loc.indexOf('?') + 1);
                        params = params.split('&');
                        for (var i = 0; i < params.length; i++) {
                            var y = params[i].split('=');
                            if(y[0] === 'oauth_verifier') {
                                verifier = y[1];
                            } else if(y[0] === 'gotOAuth.html?oauth_token') {
                                got_oauth = y[1];
                            }
                        }
                        // step 3
                        oauth.setVerifier(verifier);
                        oauth.setAccessToken([got_oauth, localStorage.getItem("oauth_token_secret")]);
    
                        var getData = {'oauth_verifier':verifier};
                        ref.close();
                        oauth.request({'method': 'GET', 'url': app.evernoteHostName + '/oauth',
                            'success': app.success, 'failure': app.failure});
                    }
                }
            );
        } else {
            // Step 4 : Get the final token
            var querystring = app.getQueryParams(data.text);
            var authTokenEvernote = querystring.oauth_token;
            // authTokenEvernote can now be used to send request to the Evernote Cloud API
            
            // Here, we connect to the Evernote Cloud API and get a list of all of the
            // notebooks in the authenticated user's account:
            var noteStoreURL = querystring.edam_noteStoreUrl;
            var noteStoreTransport = new Thrift.BinaryHttpTransport(noteStoreURL);
            var noteStoreProtocol = new Thrift.BinaryProtocol(noteStoreTransport);
            var noteStore = new NoteStoreClient(noteStoreProtocol);
            noteStore.listNotebooks(authTokenEvernote, 
                function (notebooks) {
                    console.log(notebooks);
                },
                function onerror(error) {
                    console.log(error);
                }
            );
        }
    },
    failure: function(error) {
        console.log('error ' + error.text);
    }

Here’s another tip: if you notice that the loadstart event is not triggering (which is easy to test by just commenting out the alert javascript code that’s immediately after the eventlistener), then it could be because you haven’t added the InAppBrowser plugin to your PhoneGap app. PhoneGap doesn’t make it super obvious that you need to first include this plugin, then build the app (so that your config.xml is generated correctly). But, by doing so, you’ll have the necessary web hooks and should be able to detect the loadstart event. You can find more info here. (Note that this links to v3.1.0, which is the version I tested the Evernote’s JS tutorial with.)

cordova plugin add org.apache.cordova.inappbrowser
cordova build # generates config.xml
cordova emulate android # I'm doing this as a android project

Granted, if I had just started with Evernote’s sample code in GitHub, then maybe I wouldn’t have had to debug these things (since the code in the GitHub repo is correct – I tested it). However, I wanted to use the latest versions of PhoneGap/cordova (the GitHub version is from v2.4.0; I’m using v3.1.0). Plus, I kind of feel that if you’re going to put a tutorial online for your framework and actually want people to use it, then you should make sure your documentation is kept up-to-date!

Leave a Comment

Your email address will not be published. Required fields are marked *