Skip to content

Commit

Permalink
Get app connecting to Twitter.
Browse files Browse the repository at this point in the history
  • Loading branch information
booch committed Apr 25, 2013
1 parent 810eb13 commit 64d96e6
Show file tree
Hide file tree
Showing 4 changed files with 284 additions and 5 deletions.
182 changes: 180 additions & 2 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,181 @@
window.addEventListener('error', function(msg, uri, line) {
console.log(msg + uri + line);
// These come from config.js, which comes from config.js.erb, which pulls the from the environment when building.
// TODO: Move this whole thing to config.js.erb.
var TWITTER_OPTIONS = {
consumerKey: TWITTER_OAUTH_KEY,
consumerSecret: TWITTER_OAUTH_SECRET,
callbackUrl: TWITTER_CALLBACK_URL
};


// Log all errors to the console. (But allow the normal error processing to happen as well.)
$(window).on('error', function(message, uri, line) {
console.log(message + uri + line);
});


// Start up the app.
$(document).on('deviceready', function() {
// TODO: We actually use localStorage before we get here, to define the file-global variable "accounts".
// Make sure we can store our credentials and other info. TODO: Also check to see if we get a SecurityError exception when trying to access localStorage.
if ( typeof(Storage) == 'undefined' || typeof(window.localStorage) == 'undefined' ) {
console.log('Platform does not support localStorage - quitting.');
alert('Platform does not support localStorage - quitting.');
navigator.app.exitApp();
return;
}

// Check to see if we need to run initial setup; otherwise show the main screen.
if ( no_accounts_registered() ) {
$.mobile.changePage('#setup-screen');
} else {
$.mobile.changePage('#main-screen');
}

// Set up event handlers.
$(document).on('click', '#add-twitter-account', add_twitter_account);

$(document).on('updateTweets', updateTweets);

$(document).on('accountAdded', function(event, account) {
$('ul#twitter-accounts').append('<li>' + account.name + '</li>');
});

$('#setup-screen').on('pageshow', function() {
$('ul#twitter-accounts').empty();
$.each(Object.keys(accounts['twitter']), function(index, value) {
$('ul#twitter-accounts').append('<li>' + value + '</li>');
});
});
});


// Storage of accounts. TODO: We should check for QuotaExceededError exceptions, and figure out how to handle them.
var accounts = JSON.parse(localStorage.getItem('accounts'));

var no_accounts_registered = function() {
if ( typeof(accounts) == 'undefined' || accounts == null || accounts == {} ) {
return true;
}
return ((typeof(accounts['twitter']) == 'undefined' || accounts['twitter'] == {} ) &&
(typeof(accounts['pocket']) == 'undefined' || accounts['pocket'] == {} ) &&
(typeof(accounts['google']) == 'undefined' || accounts['google'] == {} ));
};

var add_account = function(account) {
if ( typeof(accounts) == 'undefined' || accounts == null ) {
accounts = {};
}
if ( typeof(accounts[account['type']]) == 'undefined' ) {
accounts[account['type']] = {};
}
accounts[account['type']][account['name']] = account;
localStorage.setItem('accounts', JSON.stringify(accounts));
$(document).trigger('accountAdded', account);
};


var parse_query_string = function(query_string) {
var query_args = query_string.split('&');
var result = {};
for ( var i = 0; i < query_args.length; i++ ) {
var y = query_args[i].split('=');
result[y[0]] = decodeURIComponent(y[1]);
}
return result;
};


// See https://dev.twitter.com/docs/auth/implementing-sign-twitter for a better understanding of how this OAuth process works.
// This code is loosely based on http://www.mobiledevelopersolutions.com/home/start/twominutetutorials/tmt5p1
var add_twitter_account = function() {
var oauth = OAuth(TWITTER_OPTIONS);

// Get a request token.
oauth.get('https://api.twitter.com/oauth/request_token',
function(data) {
requestToken = data.text;

// TODO: Check to see that we have Internet connectivity first.

// Use PhoneGap's inBrowserApp to pop up a window to have the user authenticate to Twitter.
var twitter_oauth_window = window.open('https://api.twitter.com/oauth/authorize?'+data.text, '_blank', 'location=no');

// When the page has completed loading, check to see what URL they're at, to determine if they've completed the authentication.
// Note that we do nothing if the user goes to some other page, like the info page for the application.
$(twitter_oauth_window).bind('loadstop', function(e) {
var url = e.originalEvent.url;

// The supplied callback URL has been loaded after the user denied access to our app.
if ( url.indexOf(TWITTER_OPTIONS.callbackUrl + '?denied') >= 0 ) {
twitter_oauth_window.close();
return;
}

// The supplied callback URL has been loaded after the user authorized access to our app.
if ( url.indexOf(TWITTER_OPTIONS.callbackUrl + '?') >= 0 ) {
var params = parse_query_string(url.substr(url.indexOf('?') + 1));

// Exchange request token for access token.
oauth.get('https://api.twitter.com/oauth/access_token?oauth_verifier=' + params.oauth_verifier +'&' + requestToken,
function(data) {
var accessParams = parse_query_string(data.text);

oauth.setAccessToken([accessParams.oauth_token, accessParams.oauth_token_secret]);
oauth.get('https://api.twitter.com/1.1/account/verify_credentials.json?skip_status=true',
function(data) {
var entry = JSON.parse(data.text);
add_account({'type': 'twitter', 'name': entry.screen_name, 'token': accessParams.oauth_token, 'secret': accessParams.oauth_token_secret});
},
function(data) {
alert('Sorry, could not connect to Twitter to get user credentials.');
console.log('Error getting Twitter user credentials: ' + data);
}
);
twitter_oauth_window.close();
},
function(data) {
alert('Sorry, could not connect to Twitter to complete authentication process.');
console.log('Error getting Twitter access token: ' + data);
}
);
}
});
},
function(data) {
alert('Sorry, could not connect to Twitter to authenticate.');
console.log('Error getting Twitter request token: ' + data);
}
);
};

// TODO: Either get tweets for all accounts, or pass in which account we want to see tweets for.
var updateTweets = function (event, twitter_account_name) {
var oauth = OAuth(TWITTER_OPTIONS);
oauth.setAccessToken([accounts['twitter'][twitter_account_name].key, accounts['twitter'][twitter_account_name].secret]);
oauth.get('https://api.twitter.com/1.1/statuses/home_timeline.json',
function(data) {
var entries = JSON.parse(data.text);
var count = entries.length;
var data_html = '<h4>Home Timeline: 1 of ' + count + ' entries</h4>';

if (count >= 0) {
// Use count value to display all timelines
// for (var i = 0; i < count; i++) {
for (var i = 0; i < 1; i++) {
console.log('Got ' + count + ' tweets.');
data_html = data_html.concat('<div><img src="'
+ entries[i].user.profile_image_url + '">'
+ entries[i].user.name + '</div>');
data_html = data_html.concat('<p>' + entries[i].text + '<br>'
+ entries[i].created_at + '</p>');
}
}
$('#twitterdata').prepend($(data_html));
},
function(data) {
alert('Error getting home timeline');
console.log('Error ' + data.text);
$('#twitterdata').html('<span style="color:red;">Error getting home timeline</span>');
}
);
};
89 changes: 89 additions & 0 deletions app/assets/javascripts/childbrowser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* cordova is available under *either* the terms of the modified BSD license *or* the
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2011, IBM Corporation
*/

/**
* Constructor
*/
function ChildBrowser() {
};

ChildBrowser.CLOSE_EVENT = 0;
ChildBrowser.LOCATION_CHANGED_EVENT = 1;

/**
* Display a new browser with the specified URL.
* This method loads up a new web view in a dialog.
*
* @param url The url to load
* @param options An object that specifies additional options
*/
ChildBrowser.prototype.showWebPage = function(url, options) {
if (options === null || options === "undefined") {
var options = new Object();
options.showLocationBar = true;
}
cordova.exec(this._onEvent, this._onError, "ChildBrowser", "showWebPage", [url, options]);
};

/**
* Close the browser opened by showWebPage.
*/
ChildBrowser.prototype.close = function() {
cordova.exec(null, null, "ChildBrowser", "close", []);
};

/**
* Display a new browser with the specified URL.
* This method starts a new web browser activity.
*
* @param url The url to load
* @param usecordova Load url in cordova webview [optional]
*/
ChildBrowser.prototype.openExternal = function(url, usecordova) {
if (usecordova === true) {
navigator.app.loadUrl(url);
}
else {
cordova.exec(null, null, "ChildBrowser", "openExternal", [url, usecordova]);
}
};

/**
* Method called when the child browser has an event.
*/
ChildBrowser.prototype._onEvent = function(data) {
if (data.type == ChildBrowser.CLOSE_EVENT && typeof window.plugins.childBrowser.onClose === "function") {
window.plugins.childBrowser.onClose();
}
if (data.type == ChildBrowser.LOCATION_CHANGED_EVENT && typeof window.plugins.childBrowser.onLocationChange === "function") {
window.plugins.childBrowser.onLocationChange(data.location);
}
};

/**
* Method called when the child browser has an error.
*/
ChildBrowser.prototype._onError = function(data) {
if (typeof window.plugins.childBrowser.onError === "function") {
window.plugins.childBrowser.onError(data);
}
};

/**
* Maintain API consistency with iOS
*/
ChildBrowser.install = function(){
return window.plugins.childBrowser;
};

/**
* Load ChildBrowser
*/
cordova.addConstructor(function() {
cordova.addPlugin("childBrowser", new ChildBrowser());
});
3 changes: 3 additions & 0 deletions app/assets/javascripts/config.js.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
TWITTER_OAUTH_KEY = '<%= ENV['TWITTER_OAUTH_KEY'] %>';
TWITTER_OAUTH_SECRET = '<%= ENV['TWITTER_OAUTH_SECRET'] %>';
TWITTER_CALLBACK_URL = '<%= ENV['TWITTER_CALLBACK_URL'] %>';
15 changes: 12 additions & 3 deletions app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,23 @@
<!-- Use PhoneGap (Apache Cordova) to normalize differences between platforms. -->
<script type="text/javascript" src="assets/cordova-2.4.0.js"></script>

<!-- Pull in some common libs to make JavaScript development easier. -->
<!-- Some common libs to make JavaScript development easier. -->
<script type="text/javascript" src="assets/jquery.js"></script>
<script type="text/javascript" src="assets/jquery.mobile.js"></script>

<!-- Pull in app-specific JavaScript code. -->
<!-- WebOS code to enable menus and such. -->
<script type="text/javascript" src="assets/webos.js"></script>

<!-- JavaScript OAUTH library. -->
<script type="text/javascript" src="assets/jsOAuth-1.3.6.min.js"></script>

<!-- PhoneGap/Cordova plugins. -->
<script type="text/javascript" src="assets/childbrowser.js"></script>

<!-- App-specific JavaScript code. -->
<script type="text/javascript" src="assets/config.js"></script>
<script type="text/javascript" src="assets/application.js"></script>

<script type="text/javascript" src="assets/webos.js"></script>

</head>

Expand Down

0 comments on commit 64d96e6

Please sign in to comment.