Bug 1324062. Part 1 - Add a "Report Site Issue" button to the panel menu for NIGHTLY_BUILDs. r=Gijs

MozReview-Commit-ID: 74T8uRuqpyf

--HG--
extra : rebase_source : ae70816913cbd1510db02a47d7834248396ba78c
This commit is contained in:
Mike Taylor 2016-12-28 13:31:22 -06:00
parent 843677e75c
commit ed942c578e
26 changed files with 580 additions and 0 deletions

View File

@ -225,6 +225,12 @@ var CustomizableUIInternal = {
panelPlacements.push("characterencoding-button");
}
if (AppConstants.NIGHTLY_BUILD) {
if (Services.prefs.getBoolPref("extensions.webcompat-reporter.enabled")) {
panelPlacements.push("webcompat-reporter-button");
}
}
this.registerArea(CustomizableUI.AREA_PANEL, {
anchor: "PanelUI-menu-button",
type: CustomizableUI.TYPE_MENU_PANEL,

View File

@ -26,3 +26,9 @@ if CONFIG['MOZ_MORTAR']:
DIRS += [
'mortar',
]
# Nightly-only system add-ons
if CONFIG['NIGHTLY_BUILD']:
DIRS += [
'webcompat-reporter',
]

View File

@ -0,0 +1,46 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
let { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const WEBCOMPATREPORTER_JSM = "chrome://webcompat-reporter/content/WebCompatReporter.jsm";
XPCOMUtils.defineLazyModuleGetter(this, "WebCompatReporter",
WEBCOMPATREPORTER_JSM);
const PREF_WC_REPORTER_ENABLED = "extensions.webcompat-reporter.enabled";
let prefObserver = function(aSubject, aTopic, aData) {
let enabled = Services.prefs.getBoolPref(PREF_WC_REPORTER_ENABLED);
if (enabled) {
WebCompatReporter.init();
} else {
WebCompatReporter.uninit();
}
};
function startup(aData, aReason) {
// Observe pref changes and enable/disable as necessary.
Services.prefs.addObserver(PREF_WC_REPORTER_ENABLED, prefObserver, false);
// Only initialize if pref is enabled.
let enabled = Services.prefs.getBoolPref(PREF_WC_REPORTER_ENABLED);
if (enabled) {
WebCompatReporter.init();
}
}
function shutdown(aData, aReason) {
if (aReason === APP_SHUTDOWN) {
return;
}
Cu.unload(WEBCOMPATREPORTER_JSM);
}
function install(aData, aReason) {}
function uninstall(aData, aReason) {}

View File

@ -0,0 +1,63 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
this.EXPORTED_SYMBOLS = ["TabListener"];
let { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
"resource:///modules/CustomizableUI.jsm");
const WIDGET_ID = "webcompat-reporter-button";
// Class that watches for url/location/tab changes and enables or disables
// the Report Site Issue button accordingly
class TabListener {
constructor(win) {
this.win = win;
this.browser = win.gBrowser;
this.addListeners();
}
addListeners() {
this.browser.addTabsProgressListener(this);
this.browser.tabContainer.addEventListener("TabSelect", this);
}
removeListeners() {
this.browser.removeTabsProgressListener(this);
this.browser.tabContainer.removeEventListener("TabSelect", this);
}
handleEvent(e) {
switch (e.type) {
case "TabSelect":
this.setButtonState(e.target.linkedBrowser.currentURI.scheme);
break;
}
}
onLocationChange(browser, webProgress, request, uri, flags) {
this.setButtonState(uri.scheme);
}
static isReportableScheme(scheme) {
return ["http", "https"].some((prefix) => scheme.startsWith(prefix));
}
setButtonState(scheme) {
// Bail early if the button is in the palette.
if (!CustomizableUI.getPlacementOfWidget(WIDGET_ID)) {
return;
}
if (TabListener.isReportableScheme(scheme)) {
CustomizableUI.getWidget(WIDGET_ID).forWindow(this.win).node.removeAttribute("disabled");
} else {
CustomizableUI.getWidget(WIDGET_ID).forWindow(this.win).node.setAttribute("disabled", true);
}
}
}

View File

@ -0,0 +1,162 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
this.EXPORTED_SYMBOLS = ["WebCompatReporter"];
let { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
"resource:///modules/CustomizableUI.jsm");
XPCOMUtils.defineLazyGetter(this, "wcStrings", function() {
return Services.strings.createBundle(
"chrome://webcompat-reporter/locale/webcompat.properties");
});
const WIDGET_ID = "webcompat-reporter-button";
const TABLISTENER_JSM = "chrome://webcompat-reporter/content/TabListener.jsm";
const LIGHTBULB_CSS = "chrome://webcompat-reporter/skin/lightbulb.css";
// Weak mapping between windows and stylesheet nodes, so we can remove
// them if the button is disabled.
let styleSheetRefs = new WeakMap();
let WebCompatReporter = {
get endpoint() {
return Services.urlFormatter.formatURLPref(
"extensions.webcompat-reporter.newIssueEndpoint");
},
init() {
Cu.import(TABLISTENER_JSM);
CustomizableUI.createWidget({
id: WIDGET_ID,
label: wcStrings.GetStringFromName("wc-reporter.label"),
tooltiptext: wcStrings.GetStringFromName("wc-reporter.tooltip"),
defaultArea: CustomizableUI.AREA_PANEL,
disabled: true,
onCommand: (e) => this.reportIssue(e.target.ownerDocument),
});
for (let win of CustomizableUI.windows) {
this.onWindowOpened(win);
}
CustomizableUI.addListener(this);
},
onWindowOpened(win) {
// Attach stylesheet for the button icon.
let data = `type="text/css" href="${LIGHTBULB_CSS}"`;
let stylesheet = win.document.createProcessingInstruction(
"xml-stylesheet", data);
win.document.insertBefore(stylesheet, win.document.documentElement);
styleSheetRefs.set(win, stylesheet);
// Attach listeners to new window.
win._webcompatReporterTabListener = new TabListener(win);
},
onWindowClosed(win) {
if (win._webcompatReporterTabListener) {
win._webcompatReporterTabListener.removeListeners();
delete win._webcompatReporterTabListener;
}
},
uninit() {
CustomizableUI.destroyWidget(WIDGET_ID);
for (let win of CustomizableUI.windows) {
this.onWindowClosed(win);
let stylesheet = styleSheetRefs.get(win);
if (stylesheet) {
stylesheet.remove();
}
styleSheetRefs.delete(win);
}
CustomizableUI.removeListener(this);
Cu.unload(TABLISTENER_JSM);
},
// This method injects a framescript that should send back a screenshot blob
// of the top-level window of the currently selected tab, resolved as a
// Promise.
getScreenshot(gBrowser) {
const FRAMESCRIPT = "chrome://webcompat-reporter/content/tab-frame.js";
const TABDATA_MESSAGE = "WebCompat:SendTabData";
return new Promise((resolve) => {
let mm = gBrowser.selectedBrowser.messageManager;
mm.loadFrameScript(FRAMESCRIPT, false);
mm.addMessageListener(TABDATA_MESSAGE, function receiveFn(message) {
mm.removeMessageListener(TABDATA_MESSAGE, receiveFn);
resolve([gBrowser, message.json]);
});
});
},
// This should work like so:
// 1) set up listeners for a new webcompat.com tab, and open it, passing
// along the current URI
// 2) if we successfully got a screenshot from getScreenshot,
// inject a frame script that will postMessage it to webcompat.com
// so it can show a preview to the user and include it in FormData
// Note: openWebCompatTab arguments are passed in as an array because they
// are the result of a promise resolution.
openWebCompatTab([gBrowser, tabData]) {
const SCREENSHOT_MESSAGE = "WebCompat:SendScreenshot";
const FRAMESCRIPT = "chrome://webcompat-reporter/content/wc-frame.js";
let win = Services.wm.getMostRecentWindow("navigator:browser");
const WEBCOMPAT_ORIGIN = new win.URL(WebCompatReporter.endpoint).origin;
let tab = gBrowser.loadOneTab(
`${WebCompatReporter.endpoint}?url=${encodeURIComponent(tabData.url)}&src=desktop-reporter`,
{inBackground: false});
// If we successfully got a screenshot blob, add a listener to know when
// the new tab is loaded before sending it over.
if (tabData && tabData.blob) {
let browser = gBrowser.getBrowserForTab(tab);
let loadedListener = {
QueryInterface: XPCOMUtils.generateQI(["nsIWebProgressListener",
"nsISupportsWeakReference"]),
onStateChange(webProgress, request, flags, status) {
let isStopped = flags & Ci.nsIWebProgressListener.STATE_STOP;
let isNetwork = flags & Ci.nsIWebProgressListener.STATE_IS_NETWORK;
if (isStopped && isNetwork && webProgress.isTopLevel) {
let location;
try {
location = request.QueryInterface(Ci.nsIChannel).URI;
} catch (ex) {}
if (location && location.prePath === WEBCOMPAT_ORIGIN) {
let mm = gBrowser.selectedBrowser.messageManager;
mm.loadFrameScript(FRAMESCRIPT, false);
mm.sendAsyncMessage(SCREENSHOT_MESSAGE, {
screenshot: tabData.blob,
origin: WEBCOMPAT_ORIGIN
});
browser.removeProgressListener(this);
}
}
}
};
browser.addProgressListener(loadedListener);
}
},
reportIssue(xulDoc) {
this.getScreenshot(xulDoc.defaultView.gBrowser).then(this.openWebCompatTab)
.catch(Cu.reportError);
}
};

View File

@ -0,0 +1,37 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
let { utils: Cu } = Components;
const TABDATA_MESSAGE = "WebCompat:SendTabData";
let getScreenshot = function(win) {
return new Promise(resolve => {
let url = win.location.href;
try {
let dpr = win.devicePixelRatio;
let canvas = win.document.createElement("canvas");
let ctx = canvas.getContext("2d");
let x = win.document.documentElement.scrollLeft;
let y = win.document.documentElement.scrollTop;
let w = win.innerWidth;
let h = win.innerHeight;
canvas.width = dpr * w;
canvas.height = dpr * h;
ctx.scale(dpr, dpr);
ctx.drawWindow(win, x, y, w, h, "#fff");
canvas.toBlob(blob => {
resolve({url, blob});
});
} catch (ex) {
// CanvasRenderingContext2D.drawWindow can fail depending on memory or
// surface size. Rather than reject, resolve the URL so the user can
// file an issue without a screenshot.
Cu.reportError(`WebCompatReporter: getting a screenshot failed: ${ex}`);
resolve({url});
}
});
};
getScreenshot(content).then(data => sendAsyncMessage(TABDATA_MESSAGE, data));

View File

@ -0,0 +1,23 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
let { utils: Cu } = Components;
const SCREENSHOT_MESSAGE = "WebCompat:SendScreenshot";
addMessageListener(SCREENSHOT_MESSAGE, function handleMessage(message) {
removeMessageListener(SCREENSHOT_MESSAGE, handleMessage);
// postMessage the screenshot blob from a content Sandbox so message event.origin
// is what we expect on the client-side (i.e., https://webcompat.com)
try {
let sb = new Cu.Sandbox(content.document.nodePrincipal);
sb.win = content;
sb.screenshotBlob = Cu.cloneInto(message.data.screenshot, content);
sb.wcOrigin = Cu.cloneInto(message.data.origin, content);
Cu.evalInSandbox("win.postMessage(screenshotBlob, wcOrigin);", sb);
Cu.nukeSandbox(sb);
} catch (ex) {
Cu.reportError(`WebCompatReporter: sending a screenshot failed: ${ex}`);
}
});

View File

@ -0,0 +1,29 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
#filter substitution
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>webcompat-reporter@mozilla.org</em:id>
<em:type>2</em:type>
<em:bootstrap>true</em:bootstrap>
<em:multiprocessCompatible>true</em:multiprocessCompatible>
<em:name>WebCompat Reporter</em:name>
<em:description>Report site compatibility issues on webcompat.com.</em:description>
<em:version>1.0.0</em:version>
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>@MOZ_APP_VERSION@</em:minVersion>
<em:maxVersion>@MOZ_APP_MAXVERSION@</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View File

@ -0,0 +1,9 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
[features/webcompat-reporter@mozilla.org] chrome.jar:
% content webcompat-reporter %content/
% skin webcompat-reporter classic/1.0 %skin/
content/ (content/*)
skin/ (skin/*)

View File

@ -0,0 +1,2 @@
wc-reporter.label=Report Site Issue
wc-reporter.tooltip=Report a site compatibility issue

View File

@ -0,0 +1,8 @@
#filter substitution
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
[features/webcompat-reporter@mozilla.org] @AB_CD@.jar:
% locale webcompat-reporter @AB_CD@ %locale/@AB_CD@/
locale/@AB_CD@/ (en-US/*)

View File

@ -0,0 +1,7 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
JAR_MANIFESTS += ['jar.mn']

View File

@ -0,0 +1,22 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
DEFINES['MOZ_APP_MAXVERSION'] = CONFIG['MOZ_APP_MAXVERSION']
DIRS += ['locale']
FINAL_TARGET_FILES.features['webcompat-reporter@mozilla.org'] += [
'bootstrap.js'
]
FINAL_TARGET_PP_FILES.features['webcompat-reporter@mozilla.org'] += [
'install.rdf.in'
]
JAR_MANIFESTS += ['jar.mn']
BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']

View File

@ -0,0 +1,6 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#webcompat-reporter-button {
list-style-image: url("chrome://webcompat-reporter/skin/lightbulb.svg");
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 85 128">
<path d="M85.23,34.52v-7L43.34,35.21v6.94Zm0-16L43.34,26.28v6.94L85.23,25.5Zm-2.86-1.47v-.26A15,15,0,0,0,81.58,12h0a1.23,1.23,0,0,1-.17-.52,3.62,3.62,0,0,0-.35-.87.3.3,0,0,0-.09-.17h0A18.33,18.33,0,0,0,64.15,0C55.91,0,49,5,46.72,12h25.5L45.94,16.82l-2.6.43v7l4.08-.78Z" transform="translate(-23.46)" fill-opacity="0.6"/>
<path d="M28.65,92.41c1.7,18,14.52,30.59,35.83,30.59s34.13-12.61,35.83-30.59c1.33-18.21-4.72-23.88-12.75-35.61a36.8,36.8,0,0,1-5.23-11.57s-24.25.29-24.33,0H46.71A36.8,36.8,0,0,1,41.47,56.8C33.36,68.52,27.32,74.2,28.65,92.41Z" transform="translate(-23.46)" fill="none" stroke="#000" stroke-opacity="0.6" stroke-width="10"/>
<path d="M82.11,86.19c-.17-.26-.35-.43-.61-2L70.83,51.58c-1.13.17-.69.17-1.13.17h-.78c-.52.17-.35.78-.17,1.3L78.81,83.67a11.18,11.18,0,0,0-8-1,7.69,7.69,0,0,0-1.47.69l-4.25-1.3a8.07,8.07,0,0,0-4.94,1.65,11.54,11.54,0,0,0-2.6-1,10.73,10.73,0,0,0-7.46.52L60,53.14a3.83,3.83,0,0,0,.26-1.39c-2.25-.09-2.25.09-2.17.69L47.24,85.58a1.2,1.2,0,0,0-.26.35,1,1,0,1,0,1.56,1.21c2-2.52,4.86-3.3,8.5-2.34a5.55,5.55,0,0,1,1.65.61,5.19,5.19,0,0,0-.87,3.12c.09,2.25.87,3.82,2.08,4.42a2.16,2.16,0,0,0,2.17-.09c1-.69,1.56-2.34,1.39-4.42a5.24,5.24,0,0,0-1.65-3.38,6.35,6.35,0,0,1,6-.17,6.65,6.65,0,0,0-1.13,3.56c-.09,2,.52,3.56,1.65,4.25a2.48,2.48,0,0,0,2.34.09c1.13-.69,1.82-2.25,1.73-4.25A5.78,5.78,0,0,0,71,84.88c.17-.09.26-.09.43-.17,3-1,7.46.78,9.11,2.78a1,1,0,0,0,1.39.17A1.09,1.09,0,0,0,82.11,86.19ZM60.86,91.13h-.09a3.58,3.58,0,0,1-1-2.69,4,4,0,0,1,.52-2,3,3,0,0,1,1,2.08C61.55,90.09,61.2,91,60.86,91.13ZM69.62,91h-.09a.27.27,0,0,1-.17-.09c-.26-.17-.78-.87-.69-2.43A5.31,5.31,0,0,1,69.36,86a3.51,3.51,0,0,1,1,2.34C70.31,90.09,69.88,90.78,69.62,91Z" transform="translate(-23.46)" fill="none" stroke="#000" stroke-opacity="0.6" stroke-width="5"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,7 @@
"use strict";
module.exports = {
"extends": [
"../../../../../testing/mochitest/browser.eslintrc.js"
]
};

View File

@ -0,0 +1,9 @@
[DEFAULT]
support-files =
head.js
test.html
webcompat.html
[browser_disabled_cleanup.js]
[browser_button_state.js]
[browser_report_site_issue.js]

View File

@ -0,0 +1,28 @@
const REPORTABLE_PAGE = "http://example.com/";
const REPORTABLE_PAGE2 = "https://example.com/";
const NONREPORTABLE_PAGE = "about:blank";
/* Test that the Report Site Issue button is enabled for http and https tabs,
on page load, or TabSelect, and disabled for everything else. */
add_task(function* test_button_state_disabled() {
let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, REPORTABLE_PAGE);
yield PanelUI.show();
is(isButtonDisabled(), false, "Check that button is enabled for reportable schemes on tab load");
let tab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, NONREPORTABLE_PAGE);
is(isButtonDisabled(), true, "Check that button is disabled for non-reportable schemes on tab load");
let tab3 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, REPORTABLE_PAGE2);
is(isButtonDisabled(), false, "Check that button is enabled for reportable schemes on tab load");
yield BrowserTestUtils.switchTab(gBrowser, tab2);
is(isButtonDisabled(), true, "Check that button is disabled for non-reportable schemes on TabSelect");
yield BrowserTestUtils.switchTab(gBrowser, tab1);
is(isButtonDisabled(), false, "Check that button is enabled for reportable schemes on TabSelect");
yield BrowserTestUtils.removeTab(tab1);
yield BrowserTestUtils.removeTab(tab2);
yield BrowserTestUtils.removeTab(tab3);
});

View File

@ -0,0 +1,9 @@
// Test the addon is cleaning up after itself when disabled.
add_task(function* test_disabled() {
yield SpecialPowers.pushPrefEnv({set: [[PREF_WC_REPORTER_ENABLED, false]]});
yield BrowserTestUtils.withNewTab({gBrowser, url: "about:blank"}, function() {
is(typeof window._webCompatReporterTabListener, "undefined", "TabListener expando does not exist.");
is(document.getElementById("webcompat-reporter-button"), null, "Report Site Issue button does not exist.");
});
});

View File

@ -0,0 +1,32 @@
/* Test that clicking on the Report Site Issue button opens a new tab
and sends a postMessaged blob at it.
testing/profiles/prefs_general.js sets the value for
"extensions.webcompat-reporter.newIssueEndpoint" */
add_task(function* test_screenshot() {
yield SpecialPowers.pushPrefEnv({set: [[PREF_WC_REPORTER_ENDPOINT, NEW_ISSUE_PAGE]]});
let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE);
yield PanelUI.show();
let webcompatButton = document.getElementById("webcompat-reporter-button");
ok(webcompatButton, "Report Site Issue button exists.");
let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser);
webcompatButton.click();
let tab2 = yield newTabPromise;
yield BrowserTestUtils.waitForContentEvent(tab2.linkedBrowser, "ScreenshotReceived", false, null, true);
yield ContentTask.spawn(tab2.linkedBrowser, {TEST_PAGE}, function(args) {
let doc = content.document;
let urlParam = doc.getElementById("url").innerText;
let preview = doc.getElementById("screenshot-preview");
is(urlParam, args.TEST_PAGE, "Reported page is correctly added to the url param");
is(preview.innerText, "Pass", "A Blob object was successfully transferred to the test page.")
ok(preview.style.backgroundImage.startsWith("url(\"data:image/png;base64,iVBOR"), "A green screenshot was successfully postMessaged");
});
yield BrowserTestUtils.removeTab(tab2);
yield BrowserTestUtils.removeTab(tab1);
});

View File

@ -0,0 +1,10 @@
const PREF_WC_REPORTER_ENABLED = "extensions.webcompat-reporter.enabled";
const PREF_WC_REPORTER_ENDPOINT = "extensions.webcompat-reporter.newIssueEndpoint";
const TEST_ROOT = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://example.com");
const TEST_PAGE = TEST_ROOT + "test.html";
const NEW_ISSUE_PAGE = TEST_ROOT + "webcompat.html";
function isButtonDisabled() {
return document.getElementById("webcompat-reporter-button").disabled;
}

View File

@ -0,0 +1,5 @@
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {background: rgb(0, 128, 0);}
</style>

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<meta charset="utf-8">
<style>
#screenshot-preview {width: 200px; height: 200px;}
</style>
<div id="url"></div>
<div id="screenshot-preview">Fail</div>
<script>
let params = new URL(location.href).searchParams;
let preview = document.getElementById("screenshot-preview");
let url = document.getElementById("url");
url.innerText = params.get("url");
window.addEventListener("message", function(event) {
if (event.data instanceof Blob) {
preview.innerText = "Pass";
}
let reader = new FileReader();
reader.addEventListener("load", (e) => {
preview.style.background = `url(${e.target.result})`;
window.dispatchEvent(new CustomEvent("ScreenshotReceived", {bubbles:true}));
});
reader.readAsDataURL(event.data);
});
</script>

View File

@ -104,6 +104,9 @@ libs-%:
@$(MAKE) -B searchplugins AB_CD=$* XPI_NAME=locale-$*
@$(MAKE) libs AB_CD=$* XPI_NAME=locale-$* PREF_DIR=$(PREF_DIR)
@$(MAKE) -C $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales AB_CD=$* XPI_NAME=locale-$*
ifdef NIGHTLY_BUILD
@$(MAKE) -C ../extensions/webcompat-reporter/locale AB_CD=$* XPI_NAME=locale-$*
endif
repackage-win32-installer: WIN32_INSTALLER_OUT=$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_INST_BASENAME).exe
repackage-win32-installer: $(call ESCAPE_WILDCARD,$(WIN32_INSTALLER_IN)) $(SUBMAKEFILES) libs-$(AB_CD)

View File

@ -11,6 +11,8 @@ const {interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UITelemetry",
"resource://gre/modules/UITelemetry.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
@ -79,6 +81,12 @@ XPCOMUtils.defineLazyGetter(this, "DEFAULT_AREA_PLACEMENTS", function() {
result["PanelUI-contents"].push("characterencoding-button");
}
if (AppConstants.NIGHTLY_BUILD) {
if (Services.prefs.getBoolPref("extensions.webcompat-reporter.enabled")) {
result["PanelUI-contents"].push("webcompat-reporter-button");
}
}
return result;
});

View File

@ -4737,6 +4737,14 @@ pref("extensions.webextensions.keepUuidOnUninstall", false);
pref("extensions.webextensions.identity.redirectDomain", "extensions.allizom.org");
pref("extensions.webextensions.remote", false);
// Report Site Issue button
pref("extensions.webcompat-reporter.newIssueEndpoint", "https://webcompat.com/issues/new");
#ifdef NIGHTLY_BUILD
pref("extensions.webcompat-reporter.enabled", true);
#else
pref("extensions.webcompat-reporter.enabled", false);
#endif
pref("network.buffer.cache.count", 24);
pref("network.buffer.cache.size", 32768);