Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix widget styling bugs #3065

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 47 additions & 42 deletions src/js/contentscripts/socialwidgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -396,10 +396,6 @@ function replaceSubsequentTrackerButtonsHelper(tracker_domain) {
});
}

function _make_id(prefix) {
return prefix + "-" + Math.random().toString().replace(".", "");
}

function createReplacementWidget(widget, elToReplace) {
if (!elToReplace.parentNode) {
return null;
Expand All @@ -408,19 +404,24 @@ function createReplacementWidget(widget, elToReplace) {
let name = widget.name;

let widgetFrame = document.createElement('iframe');
let shadowHost = document.createElement("div");
shadowHost.className = "widget-shadow-host";
// Use an open shadow root on EFF test pages to allow our Selenium tests to access placeholder buttons
let shadowRoot = shadowHost.attachShadow({ mode: window.location.host === "efforg.github.io" ? "open" : "closed"});
shadowRoot.appendChild(widgetFrame);

// widget replacement frame styles
let border_width = 1;
let min_height = 210;
let styleAttrs = [
"background-color: #fff",
"border: " + border_width + "px solid #ec9329",
"min-width: 220px",
"min-height: 210px",
`min-height: ${min_height}px`,
"max-height: 600px",
"pointer-events: all",
"z-index: 999",
];
// TODO shouldn't need this (nor !important, nor _make_id, nor ...) if we use shadow DOM
let elToReplaceStyles = window.getComputedStyle(elToReplace);
if (elToReplaceStyles.position == "absolute") {
styleAttrs.push("position: absolute");
Expand Down Expand Up @@ -454,7 +455,11 @@ function createReplacementWidget(widget, elToReplace) {
}
}
}
widgetFrame.style = styleAttrs.join(" !important;") + " !important";
if (parseFloat(window.getComputedStyle(elToReplace.parentNode).height) < min_height) {
elToReplace.parentNode.style.minHeight = `${min_height}px`;
}

widgetFrame.style = styleAttrs.join(";");

let widgetDiv = document.createElement('div');

Expand All @@ -470,7 +475,7 @@ function createReplacementWidget(widget, elToReplace) {
if (TRANSLATIONS.rtl) {
styleAttrs.push("direction: rtl");
}
widgetDiv.style = styleAttrs.join(" !important;") + " !important";
widgetDiv.style = styleAttrs.join(";");

// child div styles
styleAttrs = [
Expand All @@ -484,7 +489,7 @@ function createReplacementWidget(widget, elToReplace) {
];

let textDiv = document.createElement('div');
textDiv.style = styleAttrs.join(" !important;") + " !important";
textDiv.style = styleAttrs.join(";");

let summary = TRANSLATIONS.widget_placeholder_pb_has_replaced.replace("XXX", name),
link_start = "YYY",
Expand Down Expand Up @@ -587,13 +592,13 @@ function createReplacementWidget(widget, elToReplace) {
}

let closeIcon = document.createElement('a'),
close_icon_id = _make_id("ico-close");
close_icon_id = "ico-close";
closeIcon.id = close_icon_id;
closeIcon.href = "javascript:void(0)"; // eslint-disable-line no-script-url
textDiv.appendChild(closeIcon);

let infoIcon = document.createElement('a'),
info_icon_id = _make_id("ico-help");
info_icon_id = "ico-help";
infoIcon.id = info_icon_id;
infoIcon.href = "https://privacybadger.org/#How-does-Privacy-Badger-handle-social-media-widgets";
infoIcon.rel = "noreferrer";
Expand All @@ -603,11 +608,11 @@ function createReplacementWidget(widget, elToReplace) {

let buttonDiv = document.createElement('div');
styleAttrs.push("width: 100%");
buttonDiv.style = styleAttrs.join(" !important;") + " !important";
buttonDiv.style = styleAttrs.join(";");

// allow once button
let button = document.createElement('button'),
button_id = _make_id("btn-once");
button_id = "btn-once";
button.id = button_id;
styleAttrs = [
"transition: background-color 0.25s ease-out, border-color 0.25s ease-out, color 0.25s ease-out",
Expand All @@ -626,13 +631,13 @@ function createReplacementWidget(widget, elToReplace) {
"width: 70%",
"max-width: 280px",
];
button.style = styleAttrs.join(" !important;") + " !important";
button.style = styleAttrs.join(";");

// allow on this site button
let site_button = document.createElement('button'),
site_button_id = _make_id("btn-site");
site_button_id = "btn-site";
site_button.id = site_button_id;
site_button.style = styleAttrs.join(" !important;") + " !important";
site_button.style = styleAttrs.join(";");

button.appendChild(document.createTextNode(TRANSLATIONS.allow_once));
site_button.appendChild(document.createTextNode(TRANSLATIONS.allow_on_site));
Expand All @@ -648,7 +653,7 @@ function createReplacementWidget(widget, elToReplace) {
}
let data = {
parentNode: elToReplace.parentNode,
replacement: widgetFrame,
replacement: shadowHost,
origWidgetElem: elToReplace
};
if (widget.scriptSelectors) {
Expand Down Expand Up @@ -690,36 +695,36 @@ function createReplacementWidget(widget, elToReplace) {
return;
}
e.preventDefault();
WIDGET_ELS[name] = WIDGET_ELS[name].filter(d => d.replacement != widgetFrame);
WIDGET_ELS[name] = WIDGET_ELS[name].filter(d => d.replacement != shadowHost);
doNotReplace.add(elToReplace);
widgetFrame.replaceWith(elToReplace);
shadowHost.replaceWith(elToReplace);
}, { once: true });

}, false); // end of click handler

let head_styles = `
html, body {
color: #303030 !important;
height: 100% !important;
overflow: hidden !important;
color: #303030;
height: 100%;
overflow: hidden;
}
#${button_id} {
border: 2px solid #f06a0a !important;
background-color: #f06a0a !important;
color: #fefefe !important;
border: 2px solid #f06a0a;
background-color: #f06a0a;
color: #fefefe;
}
#${site_button_id} {
border: 2px solid #333 !important;
background-color: #fefefe !important;
color: #333 !important;
border: 2px solid #333;
background-color: #fefefe;
color: #333;
}
#${button_id}:hover {
background-color: #fefefe !important;
color: #333 !important;
background-color: #fefefe;
color: #333;
}
#${site_button_id}:hover {
background-color: #fefefe !important;
border: 2px solid #f06a0a !important;
background-color: #fefefe;
border: 2px solid #f06a0a;
}
#${info_icon_id}, #${close_icon_id} {
position: absolute;
Expand Down Expand Up @@ -770,33 +775,33 @@ a:hover {
color-scheme: dark;
}
body {
background-color: #333 !important;
color: #ddd !important;
background-color: #333;
color: #ddd;
}
a, a:visited {
color: #ddd !important;
color: #ddd;
}
a:hover {
color: #f06a0a !important;
color: #f06a0a;
}
#${info_icon_id}:before, #${close_icon_id}:before {
color: #aaa;
}
#${site_button_id} {
background-color: #333 !important;
border: solid 2px #ddd !important;
color: #ddd !important;
background-color: #333;
border: solid 2px #ddd;
color: #ddd;
}
#${button_id}:hover, #${site_button_id}:hover {
background-color: #333 !important;
color: #ddd !important;
background-color: #333;
color: #ddd;
}
}
`.trim();

widgetFrame.srcdoc = '<html><head><style>' + head_styles + '</style></head><body style="margin:0">' + widgetDiv.outerHTML + '</body></html>';

return widgetFrame;
return shadowHost;
}

/**
Expand Down
20 changes: 13 additions & 7 deletions tests/selenium/widgets_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ def set_up_widgets(self):
"}(arguments[0]));"
), widgetsJson)

def switch_to_shadow_host_frame(self, selector):
shadow_host = self.find_el_by_css("div.widget-shadow-host")
shadow_root = self.driver.execute_script("return arguments[0].shadowRoot", shadow_host)
iframe = shadow_root.find_element(By.CSS_SELECTOR, selector)
self.driver.switch_to.frame(iframe)

def switch_to_frame(self, selector):
self.wait_for_and_switch_to_frame(selector, timeout=1)

Expand Down Expand Up @@ -114,13 +120,13 @@ def assert_replacement(self, widget_name=None):
widget_name = self.TYPE3_WIDGET_NAME

try:
self.switch_to_frame(f'iframe[srcdoc*="{widget_name}"]')
except (StaleElementReferenceException, TimeoutException):
self.switch_to_shadow_host_frame(f'iframe[srcdoc*="{widget_name}"]')
except (StaleElementReferenceException, TimeoutException, NoSuchElementException):
self.fail("Unable to find widget placeholder frame")

try:
self.find_el_by_css("button[id^='btn-once-']")
self.find_el_by_css("button[id^='btn-site-']")
self.find_el_by_css("button[id^='btn-once']")
self.find_el_by_css("button[id^='btn-site']")
except TimeoutException:
self.fail("Unable to find expected widget placeholder buttons")

Expand Down Expand Up @@ -151,17 +157,17 @@ def assert_no_replacement(self, widget_name=None):
if not widget_name:
widget_name = self.TYPE3_WIDGET_NAME
try:
self.switch_to_frame(f'iframe[srcdoc*="{widget_name}"]')
self.switch_to_shadow_host_frame(f'iframe[srcdoc*="{widget_name}"]')
self.fail("Widget placeholder frame should be missing")
except TimeoutException:
except (TimeoutException, NoSuchElementException):
pass
self.driver.switch_to.default_content()

def activate_widget(self, widget_name=None, once=True):
if not widget_name:
widget_name = self.TYPE3_WIDGET_NAME
id_prefix = 'btn-once' if once else 'btn-site'
self.switch_to_frame(f'iframe[srcdoc*="{widget_name}"]')
self.switch_to_shadow_host_frame(f'iframe[srcdoc*="{widget_name}"]')
self.find_el_by_css(f"button[id^='{id_prefix}']").click()
self.driver.switch_to.default_content()
# wait a bit for the widget to get reinserted
Expand Down