View difference between Paste ID: 0v2BhYdK and
SHOW: | | - or go back to the newest paste.
1-
1+
// ==UserScript==
2
// @name           Friend or Foe
3
// @version        1.0.2
4
// @author         TheRedTeam
5
// @namespace      reddit
6
// @description    Create list of friends and foes and perform actions on them
7
// @include        *reddit.com/r/*
8
// @exclude        *iframe*reddit.com/*
9
// ==/UserScript==
10
11
/*
12
Changelog:
13
09/23/10:1.0.0: First release, works decent
14
09/23/10:1.0.1: Fixed race condition if multiple tabs open
15
11/01/10:1.0.2: Fixed opacity disallowing link clicking on right floating div
16
17
*/
18
 
19
20
// current lists
21
var friend_list = [];
22
var foe_list = [];
23
var fof_user = "";
24
var fof_usercolors = []; // cache of link colors
25
26
// reddit can't handle clicking things too fast or it will miss some
27
// so we save all objects to click in an array, and use an interval on a timer
28
// this does the clicking asycronously in the background for us
29
var clicklist = new Array();
30
var clickinterval = null;
31
32
// prototype the crap out of the array object
33
Array.prototype.has = function (obj) {
34
	for (var i = 0, j = this.length; i < j; i++) {
35
		if (this[i] == obj)
36
			return true;
37
	}
38
	return false;
39
};
40
Array.prototype.remove = function(obj) {
41
  for(i=0; i<this.length; i++)
42
	if(this[i] == obj){
43
		this.splice(i, 1);
44
		i--;
45
	}
46
};
47
48
49
// get jquery from reddit
50
$ = unsafeWindow.$;
51
52
// add menu bar items
53
var mymenu = document.createElement("div");
54
mymenu.className = "sidecontentbox";
55
var side = document.getElementsByClassName("side")[0];
56
side.style.zIndex = 100;
57
side.insertBefore(mymenu,side.firstChild);
58
// we do inline CSS here to override reddit's styles because 
59
// they use the !important attribute on everything >:(
60
mymenu.innerHTML = "<div class='content' style='-moz-border-radius-bottomright: 10px; -moz-border-radius-bottomleft: 10px; border-top: 0px; background-color: #FFFFBB;'> \
61
					<div style='text-align: center; border-bottom: 1px solid #888;'><span style='font-family: arial; font-size: 14px; font-weight: bold; color: #996633;'>Friend or Foe</span></div> \
62
					<div style='margin-bottom: 5px; font-family: arial; font-size: 10px; color: #444;'><span id='fofcounts'></span> (<a href='javascript:userViewLists();'>details</a>)</div> \
63
					<ul>   \
64
						<li><a href='javascript: autoh();'>auto-hide</a></li> \
65
					</ul> \
66
					<div style='margin-top: 5px; font-family: arial; font-size: 10px; color: #444;' id='fofstatus'></div> \
67
					</div>";
68
69
70
71
72
/*
73
########################  Start Helper Functions ############################
74
*/
75
76
unsafeWindow.userViewLists = 
77
function(){
78
	alert("Friends: "+friend_list.toString()+"\n\nFoes: "+foe_list.toString());
79
};
80
81
82
function userSetCounts(){
83
	var counts = document.getElementById('fofcounts');
84
	counts.innerHTML = friend_list.length+" friends and "+foe_list.length+" foes";
85
};
86
87
// pull lists
88
function getlists(){
89
	var t1 = GM_getValue('fof_foelist','');
90
	var t2 = GM_getValue('fof_friendlist','');
91
	// see if there is a difference
92
	if(t1=='') foe_list = [];
93
	else foe_list = t1.split(',');
94
	if(t2=='') friend_list = [];
95
	else friend_list = t2.split(',');
96
}
97
98
// save changes to lists
99
function savelists(){
100
	// get current lists again to see if another tab/window updated anything
101
	var t1 = GM_getValue('fof_foelist','');
102
	var t2 = GM_getValue('fof_friendlist','');
103
	// if difference save changes
104
	if(t1 != foe_list.toString()){
105
		GM_setValue('fof_foelist',foe_list.toString());
106
	}
107
	if(t2 != friend_list.toString()){
108
		GM_setValue('fof_friendlist',friend_list.toString());
109
	}
110
}
111
112
113
114
// Add a Foe function
115
unsafeWindow.userAddFoe =  
116
function(s){ 
117
	fof_user = s;
118
	// run in timeout so we can call GM_ funcs
119
	setTimeout(
120
		function (){
121
			if(foe_list.has(fof_user)) 
122
				return;
123
			getlists();
124
			foe_list.push(fof_user);
125
			savelists();
126
			addButtons();
127
			userSetCounts();
128
			setstatus("Set '"+fof_user+"' as Foe");
129
		},
130
	0); 
131
};
132
133
// Add a Friend function
134
unsafeWindow.userAddFriend =  
135
function (s){ 
136
	fof_user = s;
137
	// run in timeout so we can call GM_ funcs
138
	setTimeout(
139
		function (){
140
			if(friend_list.has(fof_user)) 
141
				return;
142
			getlists();
143
			friend_list.push(fof_user);
144
			savelists();
145
			addButtons();
146
			userSetCounts();
147
			setstatus("Set '"+fof_user+"' as Friend");
148
		},
149
	0); 
150
};
151
152
// unset user from both friend and foe lists
153
unsafeWindow.userUnset =  
154
function (s){ 
155
	fof_user = s;
156
	// run in timeout so we can call GM_ funcs
157
	setTimeout(
158
		function (){
159
			getlists()
160
			friend_list.remove(fof_user);
161
			foe_list.remove(fof_user);
162
			savelists();
163
			addButtons();
164
			userSetCounts();
165
			setstatus("Removed '"+fof_user+"' from lists");
166
		},
167
	0); 
168
};
169
170
// create click event to use on divs and anchor tags
171
function clickevent(){
172
	var evt = document.createEvent("MouseEvents");
173
	evt.initMouseEvent("click", true, true, window,0, 0, 0, 0, 0, false, false, false, false, 0, null);
174
	return evt;
175
}
176
177
// shortcut to set the status
178
function setstatus(s){
179
	var stat = document.getElementById('fofstatus');
180
	stat.innerHTML = stat.innerHTML+s+"<br>";
181
}
182
183
// loop through and click everything in the list
184
// note we kill the interval that calls this when the list is empty
185
function clickloop(){
186
	if(clicklist.length==0){
187
		clickinterval = null;
188
		return;
189
	}
190
	var elm = clicklist.pop();
191
	elm.dispatchEvent(clickevent());
192
}
193
194
// get a css property, you'd think this would be easier... 
195
function getStyle(x,styleProp)
196
{
197
	if (x.currentStyle)
198
		var y = x.currentStyle[styleProp];
199
	else if (window.getComputedStyle)
200
		var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(styleProp);
201
	return y;
202
}
203
204
205
206
207
208
/*
209
########################  Start Main Functions ############################
210
*/
211
212
213
function addButtons(){
214
	// div that holds all the submissions
215
	var t = document.getElementsByClassName("midcol");
216
	// loop through submissions
217
	for(i=0; i < t.length; i++){
218
		// parent node is the div container for the submission
219
		submission = t[i].parentNode;
220
		// try to find the username
221
		var userbox = submission.getElementsByClassName("tagline")[0];
222
		var title = submission.getElementsByClassName("title loggedin")[0];
223
		// if in the recently viewed box (no username shown there) skip it
224
		try{
225
			var user = userbox.getElementsByTagName("a")[0];
226
		}catch(e){
227
			continue; // no username section
228
		}
229
		if(user == undefined)
230
			continue; // user is [deleted]
231
		var username = user.innerHTML;
232
		// save reddit's user colors so we can reset if needed
233
		if(fof_usercolors[username]==undefined){
234
			fof_usercolors[username] = getStyle(user, "color");
235
		}
236
		// now chose what colors to use according to the user
237
		if(foe_list.has(username)){
238
			user.style.color = fof_usercolors[username]; //"#336699"
239
			$(submission).css('opacity',0.3);
240
			submission.style.marginRight = "300px"; // opacity annoyance
241
		}
242
		else if(friend_list.has(username)){
243
			user.style.color = "#00AA00";
244
			title.style.color = "#00AA00";
245
			$(submission).css('opacity',1);
246
		}
247
		else{
248
			user.style.color = fof_usercolors[username]; //"#336699"
249
			title.style.color = "inherit";
250
			$(submission).css('opacity',1);
251
		}
252
		// see if userops is already set, if not append it
253
		var userops = userbox.getElementsByClassName("userops")[0];
254
		if(userops == undefined){
255
			userops = document.createElement("span");
256
			userops.className = "userops";
257
			userbox.appendChild(userops);
258
		}
259
		// now fill with appropriate links
260
		if(foe_list.has(username) | friend_list.has(username))
261
			userops.innerHTML = " (<a style='color: #666;' href=\"javascript:userUnset('"+username+"');\">unset</a>)";
262
		else 
263
			userops.innerHTML = " (<a style='color: #666;' href=\"javascript:userAddFoe('"+username+"');\">foe</a>|<a style='color: #666;' href=\"javascript:userAddFriend('"+username+"');\">friend</a>)";
264
	}
265
}
266
267
268
// This goes through and clicks the "hide" button on the submissions
269
// we add it to the reddit context so the link we add can call it
270
unsafeWindow.autoh =  
271
function (){
272
	// div that holds all the submissions
273
	var t = document.getElementsByClassName("midcol");
274
	var c = 0;
275
	var v = 0;
276
	// loop through submissions
277
	for(i=0; i < t.length; i++){
278
		// parent node is the div container for the submission
279
		submission = t[i].parentNode;
280
		var userbox = submission.getElementsByClassName("tagline")[0];
281
		// if in the recently viewed box (no username shown there) skip it
282
		try{
283
			var username = userbox.getElementsByTagName("a")[0].innerHTML;
284
		}catch(e){
285
			continue; // no username section
286
		}
287
		// if not a bad user, skip this iteration
288
		if(!foe_list.has(username))
289
			continue;
290
		c++;
291
		// hide it if it's down voted only
292
		if(t[i].className == "midcol dislikes"){
293
			// add object to click to the clicklist
294
			clicklist.push(submission.getElementsByClassName('state-button hide-button')[0].getElementsByTagName('a')[0]);
295
			v++;
296
		}
297
    }
298
	// start hiding (3 second time due to stupid fade out effect)
299
	clickinterval = setInterval(clickloop, 3000);
300
	// set status
301
	setstatus("Hid "+v+" of "+c+" bad submissions");
302
}; 
303
304
305
306
307
// function to perform action on submissions
308
function autov(){
309
	try{
310
	// get all submissions
311
	var t = document.getElementsByClassName("midcol");
312
	// loop through unvoted submissions
313
	var c = 0;
314
	var v = 0;
315
	for(i=0; i < t.length; i++){
316
		// parent node is the div container for the submission
317
		var submission = t[i].parentNode;
318
		// now get the appropriate objects we check
319
		var downarrow = submission.getElementsByClassName("arrow down")[0];
320
		var userbox = submission.getElementsByClassName("tagline")[0];
321
		// if in the recently viewed box (no username shown there) skip it
322
		try{
323
			var username = userbox.getElementsByTagName("a")[0].innerHTML;
324
		}catch(e){
325
			continue; // no username section
326
		}
327
		// if not a bad user, skip this iteration
328
		if(!foe_list.has(username))
329
			continue;
330
		c++;
331
		// if not already down voted, down vote it
332
		if(t[i].className == "midcol unvoted"){
333
			// save arrow to an array for down-voting later
334
			clicklist.push(downarrow);
335
			v++;
336
		}
337
    }
338
	// start down voting form the list we made (1 second timer)
339
	clickinterval = setInterval(clickloop, 1000);
340
	// set status
341
	if(c==0)
342
		setstatus("No bad submissions found");
343
	else 
344
		setstatus("Auto down voted "+v+" of "+c+" bad submissions");
345
	}
346
	catch(e){
347
		setstatus("Error: "+e);
348
	}
349
}
350
351
352
353
354
/*
355
########################  Begin auto-procedures ############################
356
*/
357
					
358
// do auto-voting only if we are on a table with submissions listed
359
if(document.getElementById('siteTable') != null){
360
	getlists();
361
	userSetCounts();
362
	autov();
363
	addButtons();
364
}