Permalink
Browse files

[toolbar] support for setting status via the toolbar

Reviewed by: ari

Notes: Time to package and release this bad boy
  • Loading branch information...
1 parent a5262f7 commit 5d8bcdaf45ab864a27df974e46ff42b078842626 Eugene Letuchy committed Dec 8, 2007
@@ -77,7 +77,7 @@ FacebookLoginClient.prototype = {
dump( 'login:' + req.responseText.indexOf("\n") + "\n" );
req.text = req.responseText.substr(req.responseText.indexOf("\n"));
var ns = req.text.match(ns_re);
- if( ns )
+ if (ns)
default xml namespace = ns;
req.xmldata = new XML(req.text);
callback(req);
View
@@ -70,6 +70,19 @@ function getAttributeById(id, attrib) {
return false;
}
+function SetFacebookStatus(status) {
+ if (fbSvc.canSetStatus) {
+ fbSvc.setStatus(status.value);
+ status.blur();
+ } else {
+ var authorizeUrl = "http://www.facebook.com/authorize.php?api_key="+fbSvc.apiKey
+ +"&v=1.0&ext_perm=status_update";
+ fbSvc.clearCanSetStatus();
+ openUILink(authorizeUrl);
+ }
+ return false;
+}
+
function OpenFBUrl(page, uid, e, params) {
var url = 'http://www.facebook.com/' + page + '?id=' + uid + '&src=fftb';
if( params ) {
@@ -81,6 +94,7 @@ function OpenFBUrl(page, uid, e, params) {
debug('Opening ' + url);
openUILink(url, e);
e.stopPropagation();
+ return false;
}
function IsSidebarOpen() {
@@ -235,7 +235,7 @@ function CreateFriendNode(list, friend, insertBefore) {
SetStatus(item, friend.status, friend.stime);
item.setAttribute('ptime', getProfileTime(friend.ptime) );
item.setAttribute('oncommand', "OpenFBUrl('profile.php', '" + friend.id + "', event, null )");
- item.setAttribute('viewUpdCmd', "OpenFBUrl('profile.php', '" + friend.id + "', event, {highlight: null} )");
+ item.setAttribute('viewUpdCmd', "OpenFBUrl('profile.php', '" + friend.id + "', event, {highlight: null} ); return false;");
item.setAttribute('msgCmd', "OpenFBUrl('message.php', '" + friend.id + "', event, null )");
item.setAttribute('pokeCmd', "OpenFBUrl('poke.php', '" + friend.id + "', event, null )");
item.setAttribute('postCmd', "OpenFBUrl('wallpost.php', '" + friend.id + "', event, null )");
View
@@ -73,20 +73,26 @@ var fbToolbarObserver = {
case 'facebook-session-start':
subject = subject.QueryInterface(Ci.fbIFacebookUser);
setAttributeById('facebook-name-info', 'label', subject.name);
+ setAttributeById('facebook-toolbar-status', 'value', subject.status);
+ var statusBox = document.getElementById('facebook-toolbar-status');
+ facebook.onStatusBoxBlur(statusBox); // cleared status autotext
+ statusBox.style.display="block";
setAttributeById('facebook-name-info', 'userid', subject.id);
setAttributeById('facebook-menu-my-profile', 'userid', subject.id);
setAttributeById('facebook-login-status', 'label', 'Logout');
var sb = GetFBSearchBox();
if (sb.value != 'Search Facebook' && sb.value != '') {
sb.value = '';
- this.searchBoxBlur(sb);
+ facebook.searchBoxBlur(sb);
}
SetHint(true, 'Loading friend list...', '');
break;
case 'facebook-session-end':
debug('ending session...');
setAttributeById('facebook-login-status', 'label', 'Login to Facebook');
setAttributeById('facebook-name-info', 'label', '');
+ var statusBox = document.getElementById('facebook-toolbar-status');
+ statusBox.style.display="none";
for each( var top in topicToXulId )
setAttributeById( top, 'label', '?');
facebook.clearFriends(true);
@@ -100,6 +106,23 @@ var fbToolbarObserver = {
subject = subject.QueryInterface(Ci.fbIFacebookUser);
facebook.updateFriend(subject);
break;
+ case 'facebook-status-set-result':
+ debug('status-set-result', data);
+ switch (data) {
+ case 'set': alert('Status was set successfully.');
+ break;
+ case 'clear': alert('Your status was cleared successfully.');
+ break;
+ case 'fail':
+ case 'perm':
+ alert('Your status could not be set.');
+ break;
+ }
+ break;
+ case 'facebook-status-updated':
+ setAttributeById('facebook-toolbar-status', 'value', subject);
+ facebook.onStatusBoxBlur(document.getElementById('facebook-toolbar-status'));
+ break;
case 'facebook-new-day':
facebook.clearFriends(false);
facebook.loadFriends();
@@ -132,6 +155,8 @@ var topics_of_interest = [ 'facebook-session-start'
, 'facebook-group-invs-updated'
, 'facebook-reqs-updated'
, 'facebook-new-day'
+ , 'facebook-status-set-result'
+ , 'facebook-status-updated'
];
var facebook = {
@@ -157,6 +182,7 @@ var facebook = {
loggedInUser = loggedInUser.QueryInterface(Ci.fbIFacebookUser);
setAttributeById('facebook-name-info', 'label', loggedInUser.name);
setAttributeById('facebook-name-info', 'userid', loggedInUser.id);
+ setAttributeById('facebook-toolbar-status', 'value', loggedInUser.status);
setAttributeById('facebook-login-status', 'label', 'Logout');
setAttributeById('facebook-menu-my-profile', 'userid', loggedInUser.id);
setAttributeById('facebook-notification-msgs', 'label', fbSvc.numMsgs);
@@ -266,6 +292,22 @@ var facebook = {
searchBox.value = 'Search Facebook';
}
},
+ isEmptyStatusText: function (text) {
+ return ('' == text || 'is ' == text || 'set your status...' == text);
+ },
+ onStatusBoxFocus: function(statusBox) {
+ if (this.isEmptyStatusText(statusBox.value)) {
+ statusBox.value = 'is ';
+ statusBox.color = '#000000';
+ }
+ statusBox.setSelectionRange(3, statusBox.value.length);
+ },
+ onStatusBoxBlur: function(statusBox) {
+ if (this.isEmptyStatusText(statusBox.value)) {
+ statusBox.color = '#808080';
+ statusBox.value = 'set your status...';
+ }
+ },
share: function() {
// not only do we need to encodeURIComponent on the string, we also need to escape quotes since
// we are putting this into a string to evaluate (as opposed to evaluating it directly)
@@ -145,6 +145,14 @@
class="button"
onclick="checkForMiddleClick(this, event);"
oncommand="if (this.label!='') OpenFBUrl('profile.php', this.getAttribute('userid'), event)" />
+ <textbox id="facebook-toolbar-status"
+ type="timed" timeout="5000" flex="10"
+ onfocus="facebook.onStatusBoxFocus(this);"
+ onblur="facebook.onStatusBoxBlur(this);"
+ oncommand="return SetFacebookStatus(this);"
+ style="display:none;"
+ tooltiptext="Change your Facebook status"
+ />
<toolbarseparator/>
<toolbarbutton id="facebook-login-status"
class="button"
@@ -1,14 +1,16 @@
<html>
-<body>
+<head>
<link rel="stylesheet" href="welcome.css" type="text/css" />
+</head>
+<body>
-<p align=right>
-<img src='arrow.png'><br>
-<font color="green">Click the login button to start!
+<p align="right">
+<img src="arrow.png" /><br />
+<font color="green"/>Click the login button to start!</font>
</p>
<div class='explanation'>
-<img src='toolbartour.png'>
+<img src='toolbartour.png' />
</div>
</body>
View
@@ -49,6 +49,11 @@ toolbar[iconsize="small"] #facebook-toolbar-toggle
padding: 0;
}
+#facebook-toolbar-status {
+ max-width: 400px;
+ min-width: 100px;
+}
+
#facebook-search .textbox-input-box {
-moz-binding: url('chrome://facebook/content/bindings.xml#facebook-search-hbox');
padding: 0px;
View
@@ -64,6 +64,9 @@ interface fbIFacebookService : nsISupports
void savedSessionStart(); // attempt to start a saved session
void sessionEnd();
+ void setStatus(in AString status);
+ void clearCanSetStatus();
+
// Use this function to help the service figure out how frequently it
// should poll facebook. If we go a while without loading any pages, it
// will back off to only 1 check per 10 minutes. If we are loading a
@@ -103,6 +106,7 @@ interface fbIFacebookService : nsISupports
// Windows can also query the most recent status of these things via the
// readonly attributes below:
readonly attribute boolean loggedIn;
+ readonly attribute boolean canSetStatus;
readonly attribute fbIFacebookUser loggedInUser;
readonly attribute long numMsgs;
readonly attribute long numPokes;
View
@@ -263,8 +263,8 @@ function facebookService()
this._winService = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
this._observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
this._prefService = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefBranch2);
- this._pwdService = Cc['@mozilla.org/passwordmanager;1'].getService(Ci.nsIPasswordManager);
- this._pwdServiceInt = Cc['@mozilla.org/passwordmanager;1'].getService(Ci.nsIPasswordManagerInternal);
+ this._pwdService = Cc['@mozilla.org/passwordmanager;1'].getService(Ci.nsIPasswordManager);
+ this._pwdServiceInt = Cc['@mozilla.org/passwordmanager;1'].getService(Ci.nsIPasswordManagerInternal);
}
facebookService.prototype = {
@@ -296,27 +296,34 @@ facebookService.prototype = {
get loggedInUser() {
return this._loggedInUser;
},
+ get canSetStatus() {
+ debug("Can Set Status", this._canSetStatus);
+ return Boolean(this._canSetStatus);
+ },
savedSessionStart: function() {
- var uid = this._prefService.getCharPref( 'extensions.facebook.uid' );
- debug( 'SAVED SESSION', uid );
- if( !uid ) return;
+ var uid = this._prefService.getCharPref('extensions.facebook.uid');
+ if (!uid) { return; }
+ debug( 'SAVED SESSION', uid );
- var session_secret = { value: "" },
- session_key = { value: "" },
- throwaway = { value: "" };
+ var session_secret = { value: "" },
+ session_key = { value: "" },
+ throwaway = { value: "" };
- this._pwdServiceInt.findPasswordEntry( PASSWORD_URL, null /* username */, null /* password */
- , throwaway /* hostURIFound */, session_key /* usernameFound */, session_secret /*pwdFound*/ );
- this.sessionStart( session_key.value, session_secret.value, uid, true );
+ this._pwdServiceInt.findPasswordEntry( PASSWORD_URL, null /* username */, null /* password */,
+ throwaway /* hostURIFound */, session_key /* usernameFound */, session_secret /*pwdFound*/ );
+ this.sessionStart( session_key.value, session_secret.value, uid, true );
},
sessionStart: function(sessionKey, sessionSecret, uid, saved) {
debug( 'sessionStart', sessionKey, sessionSecret, uid );
- if (!sessionKey || !sessionSecret || !uid) return;
+ if (!sessionKey || !sessionSecret || !uid) {
+ if (saved) {this.sessionEnd();}
+ return;
+ }
this._sessionKey = sessionKey;
this._sessionSecret = sessionSecret;
this._loggedIn = true;
this._uid = uid;
-
+
if( !saved ) {
// persist API sessions across the Firefox shutdown
// by saving them in the password store
@@ -331,6 +338,8 @@ facebookService.prototype = {
// fire off another thread to get things started
this._oneShotTimer = Cc['@mozilla.org/timer;1'].createInstance(Ci.nsITimer);
this._oneShotTimer.initWithCallback(this._initialize, 1, Ci.nsITimer.TYPE_ONE_SHOT);
+
+ this.checkCanSetStatus();
},
savePref: function( pref_name, pref_val ) {
this._prefService.unlockPref( pref_name );
@@ -340,7 +349,7 @@ facebookService.prototype = {
sessionEnd: function() {
debug('sessionEnd');
// remove session info from prefs because of explicit logout
- this.savePref( 'extensions.facebook.uid', "" );
+ this.savePref( 'extensions.facebook.uid', '' );
try { this._pwdService.removeUser( PASSWORD_URL ); }
catch( e ) { debug( 'removeUser exception' ); }
@@ -360,6 +369,7 @@ facebookService.prototype = {
this._sessionSecret = null;
this._uid = null;
this._loggedIn = false;
+ this._canSetStatus = false;
this._loggedInUser = null;
this._messages = null; // CountedNotif
@@ -369,7 +379,7 @@ facebookService.prototype = {
this._reqs = null; // SetNotif
this._friendDict = {};
- this._albumDict = {};
+ this._albumDict = {};
this._pendingRequest = false;
this._pendingRequests = [];
@@ -379,9 +389,45 @@ facebookService.prototype = {
this._lastPageLoad = 0;
this._lastCheckedFriends = 0;
},
+ setStatus: function(status) {
+ if (status == "is " || status == "set your status...") {
+ status = "";
+ }
+
+ if (status == this._loggedInUser.status) {
+ return;
+ }
+
+ if (this.canSetStatus) {
+ var is_clear = status=="";
+ var params = is_clear ? ['clear=1'] : ['status='+status, 'status_includes_verb=1'];
+ fbSvc.callMethod('facebook.users.setStatus', params, function(data) {
+ var result;
+ debug('users.setStatus:', params);
+ if ('1' == data.toString()) {
+ result = is_clear ? 'clear' : 'set';
+ } else {
+ result = 'fail';
+ }
+ fbSvc.notify(null, 'facebook-status-set-result', result);
+ });
+ } else {
+ debug("Facebook Toolbar doesn't have status_update perm?");
+ fbSvc.notify(null, 'facebook-status-set-result', 'perm' );
+ }
+ },
+ checkCanSetStatus: function() {
+ this.callMethod('facebook.users.hasAppPermission', ['ext_perm=status_update'], function(data){
+ fbSvc._canSetStatus = ('1' == data.toString());
+ debug('Can Set Status?', fbSvc._canSetStatus);
+ });
+ },
+ clearCanSetStatus: function() {
+ this._canSetStatus = null;
+ },
checkNotifications: function(onInit){
this.callMethod('facebook.notifications.get', [], function(data) {
- if( onInit ){
+ if (onInit){
fbSvc._messages = new CountedNotif( data.messages,'facebook-msgs-updated', fbSvc
, function( msgCount ) {
vdebug( "msgCount", msgCount );
@@ -419,8 +465,7 @@ facebookService.prototype = {
}
});
});
- }
- else {
+ } else {
fbSvc._messages.update( data.messages );
fbSvc._pokes.update( data.pokes );
fbSvc._groupInvs.update( data.group_invites..gid );
@@ -529,8 +574,10 @@ facebookService.prototype = {
friendDict = fbSvc.parseUsers(data);
var loggedInUser = friendDict[fbSvc._uid];
- debug( "loggedInUser", loggedInUser.name );
- delete friendDict[fbSvc._uid];
+ if (loggedInUser) {
+ debug("loggedInUser", loggedInUser.name );
+ delete friendDict[fbSvc._uid];
+ }
// Check for user's info changes
if (fbSvc._loggedInUser) {
@@ -541,13 +588,18 @@ facebookService.prototype = {
'http://www.facebook.com/profile.php?id=' + fbSvc._uid + '&src=fftb#wall');
}
}
+ if (fbSvc._loggedInUser.status != loggedInUser.status) {
+ fbSvc.notify(null, 'facebook-status-updated', loggedInUser.status);
+ }
fbSvc._loggedInUser = loggedInUser;
- } else {
+ } else if (loggedInUser){
fbSvc._loggedInUser = loggedInUser;
fbSvc.notify(fbSvc._loggedInUser, 'facebook-session-start', fbSvc._loggedInUser.id);
debug('logged in: howdy', fbSvc._loggedInUser.name);
+ } else {
+ debug("no info for logged-in user", fbSvc._uid);
}
- debug('check done with logged in user');
+ debug('check done with logged-in user');
// Check for user's friends' info changes
for each (var friend in friendDict) {
@@ -634,7 +686,7 @@ facebookService.prototype = {
},
// Note that this is intended to call non-login related Facebook API
// functions - ie things other than facebook.auth.*. The login-related
- // calls are done in the chrome layer because
+ // calls are done in the chrome layer because they are in direct response to user actions.
// Also note that this is synchronous so you should not call it from the UI.
callMethod: function (method, params, callback, secondTry) {
if (!this._loggedIn) return null;
View
Binary file not shown.
Oops, something went wrong.

0 comments on commit 5d8bcda

Please sign in to comment.