Skip to content

Commit

Permalink
Add replacement widget for Google reCAPTCHA
Browse files Browse the repository at this point in the history
  • Loading branch information
ghostwords committed Apr 23, 2020
1 parent c407b0e commit 756371a
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 6 deletions.
19 changes: 19 additions & 0 deletions src/data/socialwidgets.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,25 @@
"type": 1
}
},
"Google reCAPTCHA": {
"domain": "www.google.com",
"buttonSelectors": [
"div.g-recaptcha"
],
"scriptSelectors": [
"script[src^='//google.com/recaptcha/api.js']",
"script[src^='https://www.google.com/recaptcha/api.js']"
],
"replacementButton": {
"details": "",
"unblockDomains": [
"google.com",
"www.google.com"
],
"imagePath": "badger-play.png",
"type": 4
}
},
"LinkedIn": {
"domain": "platform.linkedin.com",
"buttonSelectors": [
Expand Down
59 changes: 53 additions & 6 deletions src/js/contentscripts/socialwidgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,14 @@ function _createReplacementButtonImageCallback(tracker, trackerElem, callback) {
// in-place widget type:
// reinitialize the widget by reinserting its element's HTML
} else if (buttonType == 3) {
let widget = createReplacementWidget(tracker.name, button, trackerElem);
let widget = createReplacementWidget(tracker, button, trackerElem, reinitializeWidgetAndUnblockTracker);
return callback(widget);

// in-place widget type:
// reinitialize the widget by reinserting its element's HTML
// and activating associated scripts
} else if (buttonType == 4) {
let widget = createReplacementWidget(tracker, button, trackerElem, replaceWidgetAndReloadScripts);
return callback(widget);
}

Expand Down Expand Up @@ -226,7 +233,7 @@ function replaceButtonWithHtmlCodeAndUnblockTracker(button, widget_name, html) {
*
* The teardown to the initialization defined in createReplacementWidget().
*
* @param {String} name the name/type of this widget (Vimeo, Disqus, etc.)
* @param {String} name the name/type of this widget (SoundCloud, Vimeo etc.)
*/
function reinitializeWidgetAndUnblockTracker(name) {
unblockTracker(name, function () {
Expand All @@ -238,6 +245,40 @@ function reinitializeWidgetAndUnblockTracker(name) {
});
}

/**
* Similar to reinitializeWidgetAndUnblockTracker() above,
* but also reruns scripts defined in scriptSelectors.
*
* @param {String} name the name/type of this widget (Disqus, Google reCAPTCHA)
*/
function replaceWidgetAndReloadScripts(name) {
unblockTracker(name, function () {
// restore all widgets of this type
WIDGET_ELS[name].forEach(data => {
data.parent.replaceChild(data.widget, data.replacement);
reloadScripts(data.scriptSelectors);
});
WIDGET_ELS[name] = [];
});
}

/**
* Replace an included script with a copy of itself to trigger a re-run.
*/
function reloadScripts(selectors) {
let scripts = document.querySelectorAll(selectors.toString());

scripts.forEach(function (scriptEl) {
let script = document.createElement("script");
script.text = scriptEl.innerHTML;
script.src = scriptEl.src;
for (let i = 0, atts = scriptEl.attributes, n = atts.length; i < n; i++) {
script.setAttribute(atts[i].nodeName, atts[i].nodeValue);
}
scriptEl.parentNode.replaceChild(script, scriptEl);
});
}

/**
* Dumping scripts into innerHTML won't execute them, so replace them
* with executable scripts.
Expand Down Expand Up @@ -290,7 +331,9 @@ function replaceSubsequentTrackerButtonsHelper(trackerDomain) {
});
}

function createReplacementWidget(name, icon, elToReplace) {
function createReplacementWidget(tracker, icon, elToReplace, activationFn) {
let name = tracker.name;

let widgetFrame = document.createElement('iframe');

// widget replacement frame styles
Expand Down Expand Up @@ -372,17 +415,21 @@ function createReplacementWidget(name, icon, elToReplace) {
if (!WIDGET_ELS.hasOwnProperty(name)) {
WIDGET_ELS[name] = [];
}
WIDGET_ELS[name].push({
let data = {
parent: elToReplace.parentNode,
widget: elToReplace,
replacement: widgetFrame
});
};
if (tracker.scriptSelectors) {
data.scriptSelectors = tracker.scriptSelectors;
}
WIDGET_ELS[name].push(data);

// set up click handler
widgetFrame.addEventListener('load', function () {
let el = widgetFrame.contentDocument.getElementById(button_id);
el.addEventListener("click", function (e) {
reinitializeWidgetAndUnblockTracker(name);
activationFn(name);
e.preventDefault();
}, { once: true });
}, false);
Expand Down

0 comments on commit 756371a

Please sign in to comment.