Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
thewickedkarma
GitHub Repository: thewickedkarma/blackeye-im
Path: blob/master/sites/bitcoin/socialwidgets.js
777 views
1
/*
2
* This file is part of Privacy Badger <https://www.eff.org/privacybadger>
3
* Copyright (C) 2014 Electronic Frontier Foundation
4
* Derived from ShareMeNot
5
* Copyright (C) 2011-2014 University of Washington
6
*
7
* Privacy Badger is free software: you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License version 3 as
9
* published by the Free Software Foundation.
10
*
11
* Privacy Badger is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
15
*
16
* You should have received a copy of the GNU General Public License
17
* along with Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
18
*/
19
20
/*
21
* ShareMeNot is licensed under the MIT license:
22
* http://www.opensource.org/licenses/mit-license.php
23
*
24
* Copyright (c) 2011-2014 University of Washington
25
*
26
* Permission is hereby granted, free of charge, to any person obtaining a
27
* copy of this software and associated documentation files (the
28
* "Software"), to deal in the Software without restriction, including
29
* without limitation the rights to use, copy, modify, merge, publish,
30
* distribute, sublicense, and/or sell copies of the Software, and to
31
* permit persons to whom the Software is furnished to do so, subject to
32
* the following conditions:
33
*
34
* The above copyright notice and this permission notice shall be included
35
* in all copies or substantial portions of the Software.
36
*
37
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
38
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
39
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
40
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
41
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
42
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
43
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
44
*/
45
46
/**
47
* Social widget tracker data, read from file.
48
*/
49
let trackerInfo;
50
51
let i18n = chrome.i18n;
52
53
54
/**
55
* Initializes the content script.
56
*/
57
function initialize() {
58
// Get tracker info and check for initial blocks (that happened
59
// before content script was attached)
60
getTrackerData(function (trackers, trackerButtonsToReplace) {
61
trackerInfo = trackers;
62
replaceInitialTrackerButtonsHelper(trackerButtonsToReplace);
63
});
64
65
// Set up listener for blocks that happen after initial check
66
chrome.runtime.onMessage.addListener(function(request/*, sender, sendResponse*/) {
67
if (request.replaceSocialWidget) {
68
replaceSubsequentTrackerButtonsHelper(request.trackerDomain);
69
}
70
});
71
}
72
73
/**
74
* Creates a replacement button element for the given tracker.
75
*
76
* @param {Tracker} tracker the Tracker object for the button
77
*
78
* @param {Element} trackerElem the tracking element that we are replacing
79
*
80
* @param {Function} callback called with the replacement button element for the tracker
81
*/
82
function createReplacementButtonImage(tracker, trackerElem, callback) {
83
var buttonData = tracker.replacementButton;
84
85
// already have replace button image URI cached
86
if (buttonData.buttonUrl) {
87
return setTimeout(function () {
88
_createReplacementButtonImageCallback(tracker, trackerElem, callback);
89
}, 0);
90
}
91
92
if (buttonData.loading) {
93
return setTimeout(function () {
94
createReplacementButtonImage(tracker, trackerElem, callback);
95
}, 10);
96
}
97
98
// don't have image data cached yet, get it from the background page
99
buttonData.loading = true;
100
chrome.runtime.sendMessage({
101
getReplacementButton: buttonData.imagePath
102
}, function (response) {
103
buttonData.buttonUrl = response; // cache image data
104
_createReplacementButtonImageCallback(tracker, trackerElem, callback);
105
});
106
}
107
108
function _createReplacementButtonImageCallback(tracker, trackerElem, callback) {
109
var buttonData = tracker.replacementButton;
110
111
var button = document.createElement("img");
112
113
var buttonUrl = buttonData.buttonUrl;
114
var buttonType = buttonData.type;
115
var details = buttonData.details;
116
117
button.setAttribute("src", buttonUrl);
118
button.setAttribute("title", i18n.getMessage("social_tooltip_pb_has_replaced") +
119
tracker.name + i18n.getMessage("social_tooltip_button"));
120
button.setAttribute(
121
"style",
122
"border: none !important; cursor: pointer !important; height: auto !important; width: auto !important;"
123
);
124
125
switch (buttonType) {
126
case 0: // normal button type; just open a new window when clicked
127
var popupUrl = details + encodeURIComponent(window.location.href);
128
129
button.addEventListener("click", function() {
130
window.open(popupUrl);
131
});
132
133
break;
134
135
// in place button type; replace the existing button
136
// with an iframe when clicked
137
case 1:
138
var iframeUrl = details + encodeURIComponent(window.location.href);
139
140
button.addEventListener("click", function() {
141
replaceButtonWithIframeAndUnblockTracker(button, buttonData.unblockDomains, iframeUrl);
142
}, { once: true });
143
144
break;
145
146
// in place button type; replace the existing button with code
147
// specified in the Trackers file
148
case 2:
149
button.addEventListener("click", function() {
150
replaceButtonWithHtmlCodeAndUnblockTracker(button, buttonData.unblockDomains, details);
151
}, { once: true });
152
break;
153
154
case 3:
155
button.addEventListener("click", function() {
156
replaceButtonWithHtmlCodeAndUnblockTracker(button, buttonData.unblockDomains, trackerElem);
157
}, { once: true });
158
break;
159
160
default:
161
throw "Invalid button type specified: " + buttonType;
162
}
163
164
callback(button);
165
}
166
167
168
/**
169
* Unblocks the given tracker and replaces the given button with an iframe
170
* pointing to the given URL.
171
*
172
* @param {Element} button the DOM element of the button to replace
173
* @param {Tracker} tracker the Tracker object for the tracker that should be
174
* unblocked
175
* @param {String} iframeUrl the URL of the iframe to replace the button
176
*/
177
function replaceButtonWithIframeAndUnblockTracker(button, tracker, iframeUrl) {
178
unblockTracker(tracker, function() {
179
// check is needed as for an unknown reason this callback function is
180
// executed for buttons that have already been removed; we are trying
181
// to prevent replacing an already removed button
182
if (button.parentNode !== null) {
183
var iframe = document.createElement("iframe");
184
185
iframe.setAttribute("src", iframeUrl);
186
iframe.setAttribute("style", "border: none !important; height: 1.5em !important;");
187
188
button.parentNode.replaceChild(iframe, button);
189
}
190
});
191
}
192
193
/**
194
* Unblocks the given tracker and replaces the given button with the
195
* HTML code defined in the provided Tracker object.
196
*
197
* @param {Element} button the DOM element of the button to replace
198
* @param {Tracker} tracker the Tracker object for the tracker that should be
199
* unblocked
200
* @param {(String|Element)} html an HTML string or DOM Element that should replace the button
201
*/
202
function replaceButtonWithHtmlCodeAndUnblockTracker(button, tracker, html) {
203
unblockTracker(tracker, function() {
204
// check is needed as for an unknown reason this callback function is
205
// executed for buttons that have already been removed; we are trying
206
// to prevent replacing an already removed button
207
if (button.parentNode !== null) {
208
var codeContainer = document.createElement("div");
209
if (typeof html == "string") {
210
codeContainer.innerHTML = html;
211
} else {
212
codeContainer.innerHTML = html.outerHTML;
213
}
214
215
button.parentNode.replaceChild(codeContainer, button);
216
217
replaceScriptsRecurse(codeContainer);
218
}
219
});
220
}
221
222
/**
223
* Dumping scripts into innerHTML won't execute them, so replace them
224
* with executable scripts.
225
*/
226
function replaceScriptsRecurse(node) {
227
if (node.getAttribute && node.getAttribute("type") == "text/javascript") {
228
var script = document.createElement("script");
229
script.text = node.innerHTML;
230
script.src = node.src;
231
node.parentNode.replaceChild(script, node);
232
} else {
233
var i = 0;
234
var children = node.childNodes;
235
while (i < children.length) {
236
replaceScriptsRecurse(children[i]);
237
i++;
238
}
239
}
240
return node;
241
}
242
243
244
/**
245
* Replaces all tracker buttons on the current web page with the internal
246
* replacement buttons, respecting the user's blocking settings.
247
*
248
* @param {Object} a map of Tracker names to Boolean values saying whether
249
* those trackers' buttons should be replaced
250
*/
251
function replaceInitialTrackerButtonsHelper(trackerButtonsToReplace) {
252
trackerInfo.forEach(function(tracker) {
253
var replaceTrackerButtons = trackerButtonsToReplace[tracker.name];
254
if (replaceTrackerButtons) {
255
replaceIndividualButton(tracker);
256
}
257
});
258
}
259
260
/**
261
* Individually replaces tracker buttons blocked after initial check.
262
*/
263
function replaceSubsequentTrackerButtonsHelper(trackerDomain) {
264
if (!trackerInfo) { return; }
265
trackerInfo.forEach(function(tracker) {
266
var replaceTrackerButtons = (tracker.domain == trackerDomain);
267
if (replaceTrackerButtons) {
268
replaceIndividualButton(tracker);
269
}
270
});
271
}
272
273
/**
274
* Actually do the work of replacing the button.
275
*/
276
function replaceIndividualButton(tracker) {
277
278
// makes a comma separated list of CSS selectors that specify
279
// buttons for the current tracker; used for document.querySelectorAll
280
var buttonSelectorsString = tracker.buttonSelectors.toString();
281
var buttonsToReplace =
282
document.querySelectorAll(buttonSelectorsString);
283
284
buttonsToReplace.forEach(function (buttonToReplace) {
285
console.log("Replacing social widget for " + tracker.name);
286
287
createReplacementButtonImage(tracker, buttonToReplace, function (button) {
288
buttonToReplace.parentNode.replaceChild(button, buttonToReplace);
289
});
290
});
291
}
292
293
/**
294
* Gets data about which tracker buttons need to be replaced from the main
295
* extension and passes it to the provided callback function.
296
*
297
* @param {Function} callback the function to call when the tracker data is
298
* received; the arguments passed are the folder
299
* containing the content script, the tracker
300
* data, and a mapping of tracker names to
301
* whether those tracker buttons need to be
302
* replaced
303
*/
304
function getTrackerData(callback) {
305
chrome.runtime.sendMessage({checkReplaceButton:document.location.hostname}, function(response) {
306
if (response) {
307
var trackers = response.trackers;
308
var trackerButtonsToReplace = response.trackerButtonsToReplace;
309
callback(trackers, trackerButtonsToReplace);
310
}
311
});
312
}
313
314
/**
315
* Unblocks the tracker with the given name from the page. Calls the
316
* provided callback function after the tracker has been unblocked.
317
*
318
* @param {String} trackerName the name of the tracker to unblock
319
* @param {Function} callback the function to call after the tracker has
320
* been unblocked
321
*/
322
function unblockTracker(buttonUrls, callback) {
323
var request = {
324
"unblockSocialWidget" : true,
325
"buttonUrls": buttonUrls
326
};
327
chrome.runtime.sendMessage(request, callback);
328
}
329
330
// END FUNCTION DEFINITIONS ///////////////////////////////////////////////////
331
332
(function () {
333
334
// don't inject into non-HTML documents (such as XML documents)
335
// but do inject into XHTML documents
336
if (document instanceof HTMLDocument === false && (
337
document instanceof XMLDocument === false ||
338
document.createElement('div') instanceof HTMLDivElement === false
339
)) {
340
return;
341
}
342
343
chrome.runtime.sendMessage({
344
checkSocialWidgetReplacementEnabled: true
345
}, function (checkSocialWidgetReplacementEnabled) {
346
if (!checkSocialWidgetReplacementEnabled) {
347
return;
348
}
349
initialize();
350
});
351
352
}());
353
354