-
Notifications
You must be signed in to change notification settings - Fork 0
/
tdbestfriends.js
257 lines (225 loc) · 6.98 KB
/
tdbestfriends.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/*!
* These Days Best Friends
* Analyses the profile feed (Wall) of the user and returns their best friends based on who posts on their wall the most.
*/
var TDBestFriends = (function() {
// Public setters
var setFB, setFriends, setUid, setPerms, extendOptions,
// Public functions
getBestFriends,
// Private variables
FB, friends, uid, perms, options = {
numToReturn : 10,
itemsPerPage : 25,
pagesToLoad : 1,
pointsWallPost : 2,
pointsComment : 1
}, feed = [], pagesLoaded = 0,
// Private functions
getLoginStatusAndLogin, loadFriends, loadFeed, calculateBestFriends, log;
/////////////////////////////////////////
// PUBLIC SETTERS
/////////////////////////////////////////
// Pass a reference to the FB Facebook SDK to reduce scope lookup
setFB = function(input) {
FB = input;
};
// Pass a reference to the friends loaded by Facebook to avoid a duplicate API call
setFriends = function(input) {
friends = input;
};
// If the user has already logged in to your app, give us their UID
setUid = function(input) {
uid = input;
};
// If your app has already called FB.login or FB.getLoginStatus, give us a list of permissions that have been granted
setPerms = function(input) {
perms = input;
};
// Override the current options
extendOptions = function(input) {
var i;
for (i in input) {
if (input.hasOwnProperty(i)) {
options[i] = input[i];
}
}
};
/////////////////////////////////////////
// PUBLIC FUNCTIONS
/////////////////////////////////////////
getBestFriends = function(callback) {
log("getBestFriends()");
// Make sure SDK exists
if (!FB) {
throw new Error("Could not find the Facebook JavaScript SDK");
}
// Make sure a user is logged in and has granted us the necessary permissions
if (!uid || !perms) {
return getLoginStatusAndLogin(getBestFriends, [callback]);
}
// Make sure the requested permissions have been granted
if (perms.indexOf("read_stream") === -1) {
return getLoginStatusAndLogin(getBestFriends, [callback]);
}
// If the friends are not set, load them
if (!friends) {
return loadFriends(getBestFriends, [callback]);
}
// If the user doesn't have any friends, return null
if (!friends.length) {
return null;
}
// Load the feed
return loadFeed(callback);
};
/////////////////////////////////////////
// PRIVATE FUNCTIONS
/////////////////////////////////////////
getLoginStatusAndLogin = function(callback, callbackArgs) {
log("getLoginStatusAndLogin()");
var login = function() {
FB.login(function(response) {
if (response.session && response.session.uid && response.perms) {
uid = response.session.uid;
perms = response.perms;
}
if (typeof callback === "function") { callback.apply(this, callbackArgs); }
}, { perms: "read_stream" });
};
FB.getLoginStatus(function(response) {
if (response.session && response.session.uid && response.perms) {
uid = response.session.uid;
perms = response.perms;
if (typeof callback === "function") { callback.apply(this, callbackArgs); }
} else {
login();
}
});
};
// Load the friends then call the callback
loadFriends = function(callback, callbackArgs) {
log("loadFriends()");
FB.api("/me/friends?fields=id,name", function(response) {
if (response.data) {
friends = response.data;
}
if (typeof callback === "function") { callback.apply(this, callbackArgs); }
});
};
// Load the feed then call the callback
loadFeed = function(callback) {
log("loadFeed()");
FB.api("/me/feed?limit=" + options.itemsPerPage.toString() + "&offset=" + (pagesLoaded * options.itemsPerPage).toString(), function(response) {
if (response.data) {
feed = feed.concat(response.data);
pagesLoaded += 1;
if (pagesLoaded === options.pagesToLoad || response.data.length < options.itemsPerPage) {
// Determine the best friends
return calculateBestFriends(callback);
} else {
loadFeed(callback);
}
}
});
};
// Read the news feed and figure out who the best friends are
calculateBestFriends = function(callback) {
var points = [], pointsById = {}, friend, bestFriends = [], i, iLen, post, j, jLen, comment, sortByPoints, complete, padOutResults;
for (i = 0, iLen = feed.length; i < iLen; i += 1) {
post = feed[i];
if (post.from) {
friend = pointsById[post.from.id];
if (friend) {
friend.points += options.pointsWallPost;
} else {
friend = { id: post.from.id, points: options.pointsWallPost };
pointsById[friend.id] = points[points.push(friend) - 1];
}
//log("Incremented " + post.from.name + "'s points for a wall post to " + friend.points);
}
if (post.comments && post.comments.data) {
for (j = 0, jLen = post.comments.data.length; j < jLen; j += 1) {
comment = post.comments.data[j];
if (comment.from) {
friend = pointsById[comment.from.id];
if (friend) {
friend.points += options.pointsWallPost;
} else {
friend = { id: comment.from.id, points: options.pointsComment };
pointsById[friend.id] = points[points.push(friend) - 1];
}
//log("Incremented " + comment.from.name + "'s points for a comment to " + friend.points);
}
}
}
}
pointsById = null;
// Sort the friends with points
sortByPoints = function(a, b) {
if (a.points < b.points) {
return 1;
} else if (a.points > b.points) {
return -1;
} else {
return 0;
}
};
points.sort(sortByPoints);
complete = function() {
callback.apply(this, [bestFriends]);
};
// Add the top scoring people to the bestFriendsArray if they are friends with the user
for (i = 0, iLen = points.length; i < iLen; i += 1) {
if (points[i].id !== uid) {
for (j = 0, jLen = friends.length; j < jLen; j += 1) {
if (points[i].id === friends[j].id) {
bestFriends.push(friends[j]);
if (bestFriends.length === options.numToReturn) {
return complete();
}
break;
}
}
}
}
// Add some extra random friends to pad out the result list if necessary
padOutResults = function() {
var unusedFriends = [], i, iLen, j, jLen, found, rand;
// Generate a list of unused friends
for (i = 0, iLen = friends.length; i < iLen; i += 1) {
found = false;
for (j = 0, jLen = bestFriends.length; j < jLen; j += 1) {
if (friends[i].id === bestFriends[j].id) {
found = true;
break;
}
}
if (!found) {
unusedFriends.push(friends[i]);
}
}
// Add as many unused friends as we need
while (bestFriends.length < options.numToReturn) {
rand = Math.floor(Math.random() * unusedFriends.length);
friend = unusedFriends.splice(rand, 1);
bestFriends.push(friend[0]);
}
};
padOutResults();
return complete();
};
log = function() {
if (console) {
console.log(Array.prototype.slice.call(arguments));
}
};
return {
setFB : setFB,
setFriends : setFriends,
setUid : setUid,
setPerms : setPerms,
extendOptions : extendOptions,
getBestFriends : getBestFriends
};
}());