Bug 1498410 - Part 3 - Export Screenshots 35.0.0 (code excluding translations and Raven upgrade); r=aswan,ianbicking

MozReview-Commit-ID: IF010Y5ERks

Differential Revision: https://phabricator.services.mozilla.com/D8505

--HG--
rename : browser/extensions/screenshots/webextension/assertIsBlankDocument.js => browser/extensions/screenshots/assertIsBlankDocument.js
rename : browser/extensions/screenshots/webextension/assertIsTrusted.js => browser/extensions/screenshots/assertIsTrusted.js
rename : browser/extensions/screenshots/webextension/background/analytics.js => browser/extensions/screenshots/background/analytics.js
rename : browser/extensions/screenshots/webextension/background/auth.js => browser/extensions/screenshots/background/auth.js
rename : browser/extensions/screenshots/webextension/background/communication.js => browser/extensions/screenshots/background/communication.js
rename : browser/extensions/screenshots/webextension/background/deviceInfo.js => browser/extensions/screenshots/background/deviceInfo.js
rename : browser/extensions/screenshots/webextension/background/main.js => browser/extensions/screenshots/background/main.js
rename : browser/extensions/screenshots/webextension/background/selectorLoader.js => browser/extensions/screenshots/background/selectorLoader.js
rename : browser/extensions/screenshots/webextension/background/senderror.js => browser/extensions/screenshots/background/senderror.js
rename : browser/extensions/screenshots/webextension/background/startBackground.js => browser/extensions/screenshots/background/startBackground.js
rename : browser/extensions/screenshots/webextension/background/takeshot.js => browser/extensions/screenshots/background/takeshot.js
rename : browser/extensions/screenshots/webextension/blank.html => browser/extensions/screenshots/blank.html
rename : browser/extensions/screenshots/webextension/blobConverters.js => browser/extensions/screenshots/blobConverters.js
rename : browser/extensions/screenshots/webextension/build/buildSettings.js => browser/extensions/screenshots/build/buildSettings.js
rename : browser/extensions/screenshots/webextension/build/inlineSelectionCss.js => browser/extensions/screenshots/build/inlineSelectionCss.js
rename : browser/extensions/screenshots/webextension/build/onboardingCss.js => browser/extensions/screenshots/build/onboardingCss.js
rename : browser/extensions/screenshots/webextension/build/onboardingHtml.js => browser/extensions/screenshots/build/onboardingHtml.js
rename : browser/extensions/screenshots/webextension/build/selection.js => browser/extensions/screenshots/build/selection.js
rename : browser/extensions/screenshots/webextension/build/shot.js => browser/extensions/screenshots/build/shot.js
rename : browser/extensions/screenshots/webextension/build/thumbnailGenerator.js => browser/extensions/screenshots/build/thumbnailGenerator.js
rename : browser/extensions/screenshots/webextension/catcher.js => browser/extensions/screenshots/catcher.js
rename : browser/extensions/screenshots/webextension/clipboard.js => browser/extensions/screenshots/clipboard.js
rename : browser/extensions/screenshots/webextension/domainFromUrl.js => browser/extensions/screenshots/domainFromUrl.js
rename : browser/extensions/screenshots/webextension/icons/back-highlight.svg => browser/extensions/screenshots/icons/back-highlight.svg
rename : browser/extensions/screenshots/webextension/icons/back.svg => browser/extensions/screenshots/icons/back.svg
rename : browser/extensions/screenshots/webextension/icons/cancel.svg => browser/extensions/screenshots/icons/cancel.svg
rename : browser/extensions/screenshots/webextension/icons/cloud.svg => browser/extensions/screenshots/icons/cloud.svg
rename : browser/extensions/screenshots/webextension/icons/copied-notification.svg => browser/extensions/screenshots/icons/copied-notification.svg
rename : browser/extensions/screenshots/webextension/icons/copy.svg => browser/extensions/screenshots/icons/copy.svg
rename : browser/extensions/screenshots/webextension/icons/done.svg => browser/extensions/screenshots/icons/done.svg
rename : browser/extensions/screenshots/webextension/icons/download.svg => browser/extensions/screenshots/icons/download.svg
rename : browser/extensions/screenshots/webextension/icons/help-16.svg => browser/extensions/screenshots/icons/help-16.svg
rename : browser/extensions/screenshots/webextension/icons/icon-highlight-32-v2.svg => browser/extensions/screenshots/icons/icon-highlight-32-v2.svg
rename : browser/extensions/screenshots/webextension/icons/icon-v2.svg => browser/extensions/screenshots/icons/icon-v2.svg
rename : browser/extensions/screenshots/webextension/icons/icon-welcome-face-without-eyes.svg => browser/extensions/screenshots/icons/icon-welcome-face-without-eyes.svg
rename : browser/extensions/screenshots/webextension/icons/menu-fullpage.svg => browser/extensions/screenshots/icons/menu-fullpage.svg
rename : browser/extensions/screenshots/webextension/icons/menu-myshot-white.svg => browser/extensions/screenshots/icons/menu-myshot-white.svg
rename : browser/extensions/screenshots/webextension/icons/menu-myshot.svg => browser/extensions/screenshots/icons/menu-myshot.svg
rename : browser/extensions/screenshots/webextension/icons/menu-visible.svg => browser/extensions/screenshots/icons/menu-visible.svg
rename : browser/extensions/screenshots/webextension/icons/onboarding-1.png => browser/extensions/screenshots/icons/onboarding-1.png
rename : browser/extensions/screenshots/webextension/icons/onboarding-2.png => browser/extensions/screenshots/icons/onboarding-2.png
rename : browser/extensions/screenshots/webextension/icons/onboarding-4.png => browser/extensions/screenshots/icons/onboarding-4.png
rename : browser/extensions/screenshots/webextension/icons/onboarding-5.png => browser/extensions/screenshots/icons/onboarding-5.png
rename : browser/extensions/screenshots/webextension/log.js => browser/extensions/screenshots/log.js
rename : browser/extensions/screenshots/webextension/makeUuid.js => browser/extensions/screenshots/makeUuid.js
rename : browser/extensions/screenshots/webextension/manifest.json => browser/extensions/screenshots/manifest.json
rename : browser/extensions/screenshots/webextension/onboarding/slides.html => browser/extensions/screenshots/onboarding/slides.html
rename : browser/extensions/screenshots/webextension/onboarding/slides.js => browser/extensions/screenshots/onboarding/slides.js
rename : browser/extensions/screenshots/webextension/randomString.js => browser/extensions/screenshots/randomString.js
rename : browser/extensions/screenshots/webextension/selector/callBackground.js => browser/extensions/screenshots/selector/callBackground.js
rename : browser/extensions/screenshots/webextension/selector/documentMetadata.js => browser/extensions/screenshots/selector/documentMetadata.js
rename : browser/extensions/screenshots/webextension/selector/shooter.js => browser/extensions/screenshots/selector/shooter.js
rename : browser/extensions/screenshots/webextension/selector/ui.js => browser/extensions/screenshots/selector/ui.js
rename : browser/extensions/screenshots/webextension/selector/uicontrol.js => browser/extensions/screenshots/selector/uicontrol.js
rename : browser/extensions/screenshots/webextension/selector/util.js => browser/extensions/screenshots/selector/util.js
rename : browser/extensions/screenshots/webextension/sitehelper.js => browser/extensions/screenshots/sitehelper.js
extra : moz-landing-system : lando
This commit is contained in:
Jared Hirsch 2018-10-12 21:42:27 +00:00
Родитель f536efe3aa
Коммит f1e59d5af1
67 изменённых файлов: 726 добавлений и 768 удалений

Просмотреть файл

@ -1,4 +1,4 @@
/* globals main, auth, catcher, deviceInfo, communication, log */
/* globals main, auth, browser, catcher, deviceInfo, communication, log */
"use strict";
@ -128,14 +128,22 @@ this.analytics = (function() {
return Promise.resolve();
};
exports.refreshTelemetryPref = function() {
return communication.sendToBootstrap("isTelemetryEnabled").then((result) => {
telemetryPrefKnown = true;
if (result === communication.NO_BOOTSTRAP) {
telemetryEnabled = true;
} else {
telemetryEnabled = result;
exports.incrementCount = function(scalar) {
const allowedScalars = ["download", "upload", "copy"];
if (!allowedScalars.includes(scalar)) {
const err = `incrementCount passed an unrecognized scalar ${scalar}`;
log.warn(err);
return Promise.resolve();
}
return browser.telemetry.scalarAdd(`screenshots.${scalar}`, 1).catch(err => {
log.warn(`incrementCount failed with error: ${err}`);
});
};
exports.refreshTelemetryPref = function() {
return browser.telemetry.canUpload().then((result) => {
telemetryPrefKnown = true;
telemetryEnabled = result;
}, (error) => {
// If there's an error reading the pref, we should assume that we shouldn't send data
telemetryPrefKnown = true;

Просмотреть файл

@ -11,19 +11,26 @@ this.auth = (function() {
let authHeader = null;
let sentryPublicDSN = null;
let abTests = {};
let accountId = null;
const registrationInfoFetched = catcher.watchPromise(browser.storage.local.get(["registrationInfo", "abTests"]).then((result) => {
const fetchStoredInfo = catcher.watchPromise(
browser.storage.local.get(["registrationInfo", "abTests"]).then((result) => {
if (result.abTests) {
abTests = result.abTests;
}
if (result.registrationInfo) {
registrationInfo = result.registrationInfo;
} else {
}
}));
function getRegistrationInfo() {
if (!registrationInfo) {
registrationInfo = generateRegistrationInfo();
log.info("Generating new device authentication ID", registrationInfo);
browser.storage.local.set({registrationInfo});
}
}));
return registrationInfo;
}
exports.getDeviceId = function() {
return registrationInfo && registrationInfo.deviceId;
@ -77,6 +84,8 @@ this.auth = (function() {
function login(options) {
const { ownershipCheck, noRegister } = options || {};
return new Promise((resolve, reject) => {
return fetchStoredInfo.then(() => {
const registrationInfo = getRegistrationInfo();
const loginUrl = main.getBackend() + "/api/login";
// TODO: replace xhr with Fetch #2261
const req = new XMLHttpRequest();
@ -124,12 +133,14 @@ this.auth = (function() {
deviceId: registrationInfo.deviceId,
secret: registrationInfo.secret,
deviceInfo: JSON.stringify(deviceInfo()),
ownershipCheck
ownershipCheck,
}));
});
});
}
function saveAuthInfo(responseJson) {
accountId = responseJson.accountId;
if (responseJson.sentryPublicDSN) {
sentryPublicDSN = responseJson.sentryPublicDSN;
}
@ -146,8 +157,12 @@ this.auth = (function() {
}
}
exports.getDeviceId = function() {
return registrationInfo.deviceId;
exports.maybeLogin = function() {
if (!registrationInfo) {
return Promise.resolve();
}
return exports.authHeaders();
};
exports.authHeaders = function() {
@ -173,20 +188,25 @@ this.auth = (function() {
};
exports.isRegistered = function() {
return registrationInfo.registered;
return registrationInfo && registrationInfo.registered;
};
communication.register("getAuthInfo", (sender, ownershipCheck) => {
return registrationInfoFetched.then(() => {
return exports.authHeaders();
}).then((authHeaders) => {
return fetchStoredInfo.then(() => {
// If a device id was never generated, report back accordingly.
if (!registrationInfo) {
return null;
}
return exports.authHeaders().then((authHeaders) => {
let info = registrationInfo;
if (info.registered) {
return login({ownershipCheck}).then((result) => {
return {
isOwner: result && result.isOwner,
deviceId: registrationInfo.deviceId,
authHeaders
accountId,
authHeaders,
};
});
}
@ -194,6 +214,7 @@ this.auth = (function() {
return info;
});
});
});
return exports;
})();

Просмотреть файл

@ -45,34 +45,5 @@ this.communication = (function() {
registeredFunctions[name] = func;
};
/** Send a message to bootstrap.js
Technically any worker can listen to this. If the bootstrap wrapper is not in place, then this
will *not* fail, and will return a value of exports.NO_BOOTSTRAP */
exports.sendToBootstrap = function(funcName, ...args) {
return browser.runtime.sendMessage({funcName, args}).then((result) => {
if (result.type === "success") {
return result.value;
}
throw new Error(`Error in ${funcName}: ${result.name || "unknown"}`);
}, (error) => {
if (isBootstrapMissingError(error)) {
return exports.NO_BOOTSTRAP;
}
throw error;
});
};
function isBootstrapMissingError(error) {
if (!error) {
return false;
}
return ("errorCode" in error && error.errorCode === "NO_RECEIVING_END") ||
(!error.errorCode && error.message === "Could not establish connection. Receiving end does not exist.");
}
// A singleton/sentinel (with a name):
exports.NO_BOOTSTRAP = {name: "communication.NO_BOOTSTRAP"};
return exports;
})();

Просмотреть файл

@ -6,7 +6,7 @@ this.main = (function() {
const exports = {};
const pasteSymbol = (window.navigator.platform.match(/Mac/i)) ? "\u2318" : "Ctrl";
const { sendEvent } = analytics;
const { sendEvent, incrementCount } = analytics;
const manifest = browser.runtime.getManifest();
let backend;
@ -71,7 +71,7 @@ this.main = (function() {
if (!isLoaded) {
sendEvent("start-shot", "site-request", {incognito: tab.incognito});
setIconActive(true, tab.id);
selectorLoader.toggle(tab.id, false);
selectorLoader.toggle(tab.id, Promise.resolve(false));
}
});
}
@ -96,7 +96,7 @@ this.main = (function() {
sendEvent("goto-myshots", "about-newtab", {incognito: tab.incognito});
}));
catcher.watchPromise(
auth.authHeaders()
auth.maybeLogin()
.then(() => browser.tabs.update({url: backend + "/shots"})));
} else {
catcher.watchPromise(
@ -189,7 +189,7 @@ this.main = (function() {
communication.register("openMyShots", (sender) => {
return catcher.watchPromise(
auth.authHeaders()
auth.maybeLogin()
.then(() => browser.tabs.create({url: backend + "/shots"})));
});
@ -229,7 +229,7 @@ this.main = (function() {
return blobConverters.blobToArray(blob).then(buffer => {
return browser.clipboard.setImageData(
buffer, blob.type.split("/", 2)[1]).then(() => {
catcher.watchPromise(communication.sendToBootstrap("incrementCount", {scalar: "copy"}));
catcher.watchPromise(incrementCount("copy"));
return browser.notifications.create({
type: "basic",
iconUrl: "../icons/copied-notification.svg",
@ -256,7 +256,7 @@ this.main = (function() {
}
});
browser.downloads.onChanged.addListener(onChangedCallback);
catcher.watchPromise(communication.sendToBootstrap("incrementCount", {scalar: "download"}));
catcher.watchPromise(incrementCount("download"));
return browser.windows.getLastFocused().then(windowInfo => {
return browser.downloads.download({
url,
@ -301,5 +301,10 @@ this.main = (function() {
}));
});
// This allows the web site show notifications through sitehelper.js
communication.register("showNotification", (sender, notification) => {
return browser.notifications.create(notification);
});
return exports;
})();

Просмотреть файл

@ -89,13 +89,12 @@ this.selectorLoader = (function() {
}));
};
// TODO: since bootstrap communication is now required, would this function
// make more sense inside background/main?
function downloadOnlyCheck(tabId) {
return communication.sendToBootstrap("isHistoryEnabled").then((historyEnabled) => {
return communication.sendToBootstrap("isUploadDisabled").then((uploadDisabled) => {
return browser.experiments.screenshots.isHistoryEnabled().then((historyEnabled) => {
return browser.experiments.screenshots.isUploadDisabled().then((uploadDisabled) => {
return browser.experiments.screenshots.getUpdateChannel().then((channel) => {
return browser.tabs.get(tabId).then(tab => {
const downloadOnly = !historyEnabled || uploadDisabled || tab.incognito;
const downloadOnly = !historyEnabled || uploadDisabled || channel === "esr" || tab.incognito;
return browser.tabs.executeScript(tabId, {
// Note: `window` here refers to a global accessible to content
// scripts, but not the scripts in the underlying page. For more
@ -106,6 +105,7 @@ this.selectorLoader = (function() {
});
});
});
});
}
function executeModules(tabId, scripts) {

Просмотреть файл

@ -52,6 +52,8 @@ this.startBackground = (function() {
});
});
browser.experiments.screenshots.initLibraryButton();
browser.runtime.onMessage.addListener((req, sender, sendResponse) => {
loadIfNecessary().then(() => {
return communication.onMessage(req, sender, sendResponse);

Просмотреть файл

@ -5,12 +5,11 @@
this.takeshot = (function() {
const exports = {};
const Shot = shot.AbstractShot;
const { sendEvent } = analytics;
const { sendEvent, incrementCount } = analytics;
communication.register("takeShot", catcher.watchFunction((sender, options) => {
const { captureType, captureText, scroll, selectedPos, shotId } = options;
const shot = new Shot(main.getBackend(), shotId, options.shot);
shot.favicon = sender.tab.favIconUrl;
let imageBlob = options.imageBlob;
let capturePromise = Promise.resolve();
let openedTab;
@ -56,7 +55,9 @@ this.takeshot = (function() {
} else {
shot.thumbnail = thumbnailImage;
}
}).then(() => {
return browser.experiments.screenshots.getUpdateChannel();
}).then((firefoxChannel) => {
shot.firefoxChannel = firefoxChannel;
return browser.tabs.create({url: shot.creatingUrl});
}).then((tab) => {
openedTab = tab;
@ -76,7 +77,7 @@ this.takeshot = (function() {
}
);
}).then(() => {
catcher.watchPromise(communication.sendToBootstrap("incrementCount", {scalar: "upload"}));
catcher.watchPromise(incrementCount("upload"));
return shot.viewUrl;
}).catch((error) => {
browser.tabs.remove(openedTab.id);

215
browser/extensions/screenshots/bootstrap.js поставляемый
Просмотреть файл

@ -1,215 +0,0 @@
/* globals ADDON_DISABLE Services CustomizableUI LegacyExtensionsUtils AppConstants PageActions */
const ADDON_ID = "screenshots@mozilla.org";
const TELEMETRY_ENABLED_PREF = "datareporting.healthreport.uploadEnabled";
const PREF_BRANCH = "extensions.screenshots.";
const USER_DISABLE_PREF = "extensions.screenshots.disabled";
const UPLOAD_DISABLED_PREF = "extensions.screenshots.upload-disabled";
const HISTORY_ENABLED_PREF = "places.history.enabled";
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.defineModuleGetter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm");
ChromeUtils.defineModuleGetter(this, "AddonManagerPrivate",
"resource://gre/modules/AddonManager.jsm");
ChromeUtils.defineModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
ChromeUtils.defineModuleGetter(this, "CustomizableUI",
"resource:///modules/CustomizableUI.jsm");
ChromeUtils.defineModuleGetter(this, "LegacyExtensionsUtils",
"resource://gre/modules/LegacyExtensionsUtils.jsm");
ChromeUtils.defineModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
let addonResourceURI;
let appStartupDone;
let appStartupPromise = new Promise((resolve, reject) => {
appStartupDone = resolve;
});
const prefs = Services.prefs;
const appStartupObserver = {
register() {
Services.obs.addObserver(this, "sessionstore-windows-restored", false); // eslint-disable-line mozilla/no-useless-parameters
},
unregister() {
Services.obs.removeObserver(this, "sessionstore-windows-restored", false); // eslint-disable-line mozilla/no-useless-parameters
},
observe() {
appStartupDone();
this.unregister();
}
};
const LibraryButton = {
ITEM_ID: "appMenu-library-screenshots",
init(webExtension) {
this._initialized = true;
const permissionPages = [...webExtension.extension.permissions].filter(p => (/^https?:\/\//i).test(p));
if (permissionPages.length > 1) {
Cu.reportError(new Error("Should not have more than 1 permission page, but got: " + JSON.stringify(permissionPages)));
}
this.PAGE_TO_OPEN = permissionPages.length === 1 ? permissionPages[0].replace(/\*$/, "") : "https://screenshots.firefox.com/";
this.PAGE_TO_OPEN += "shots";
this.ICON_URL = webExtension.extension.getURL("icons/icon-v2.svg");
this.LABEL = webExtension.extension.localizeMessage("libraryLabel");
CustomizableUI.addListener(this);
for (const win of CustomizableUI.windows) {
this.onWindowOpened(win);
}
},
uninit() {
if (!this._initialized) {
return;
}
for (const win of CustomizableUI.windows) {
const item = win.document.getElementById(this.ITEM_ID);
if (item) {
item.remove();
}
}
CustomizableUI.removeListener(this);
this._initialized = false;
},
onWindowOpened(win) {
const libraryViewInsertionPoint = win.document.getElementById("appMenu-library-remotetabs-button");
// If the library view doesn't exist (on non-photon builds, for instance),
// this will be null, and we bail out early.
if (!libraryViewInsertionPoint) {
return;
}
const parent = libraryViewInsertionPoint.parentNode;
const {nextSibling} = libraryViewInsertionPoint;
const item = win.document.createXULElement("toolbarbutton");
item.className = "subviewbutton subviewbutton-iconic";
item.addEventListener("command", () => win.openWebLinkIn(this.PAGE_TO_OPEN, "tab"));
item.id = this.ITEM_ID;
const iconURL = this.ICON_URL;
item.setAttribute("image", iconURL);
item.setAttribute("label", this.LABEL);
parent.insertBefore(item, nextSibling);
},
};
let addonData, startupReason;
function startup(data, reason) { // eslint-disable-line no-unused-vars
addonResourceURI = data.resourceURI;
if (Services.prefs.getBoolPref(USER_DISABLE_PREF, false)) {
AddonManager.getActiveAddons().then(result => {
let addon = result.addons.find(a => a.id == ADDON_ID);
if (addon) {
addon.disable({allowSystemAddons: true});
}
});
return;
}
addonData = data;
startupReason = reason;
if (reason === AddonManagerPrivate.BOOTSTRAP_REASONS.APP_STARTUP) {
appStartupObserver.register();
} else {
appStartupDone();
}
// eslint-disable-next-line promise/catch-or-return
appStartupPromise = appStartupPromise.then(handleStartup);
}
function shutdown(data, reason) { // eslint-disable-line no-unused-vars
const webExtension = LegacyExtensionsUtils.getEmbeddedExtensionFor({
id: ADDON_ID,
resourceURI: addonResourceURI
});
// Immediately exit if Firefox is exiting, #3323
if (reason === AddonManagerPrivate.BOOTSTRAP_REASONS.APP_SHUTDOWN) {
stop(webExtension, reason);
return;
}
// Because the prefObserver is unregistered above, this _should_ terminate the promise chain.
appStartupPromise = appStartupPromise.then(() => { stop(webExtension, reason); });
}
function install(data, reason) {} // eslint-disable-line no-unused-vars
function uninstall(data, reason) {} // eslint-disable-line no-unused-vars
function getBoolPref(pref) {
return prefs.getPrefType(pref) && prefs.getBoolPref(pref);
}
function handleStartup() {
const webExtension = LegacyExtensionsUtils.getEmbeddedExtensionFor({
id: ADDON_ID,
resourceURI: addonResourceURI
});
if (!webExtension.started) {
start(webExtension);
}
}
function start(webExtension) {
let reasonStr = stringReasonFromNumericReason(startupReason);
return webExtension.startup(reasonStr, addonData).then((api) => {
api.browser.runtime.onMessage.addListener(handleMessage);
LibraryButton.init(webExtension);
}).catch((err) => {
// The startup() promise will be rejected if the webExtension was
// already started (a harmless error), or if initializing the
// WebExtension failed and threw (an important error).
console.error(err);
if (err.message !== "This embedded extension has already been started") {
// TODO: Should we send these errors to Sentry? #2420
}
});
}
function stop(webExtension, reason) {
if (reason !== AddonManagerPrivate.BOOTSTRAP_REASONS.APP_SHUTDOWN) {
LibraryButton.uninit();
}
let reasonStr = stringReasonFromNumericReason(reason);
return Promise.resolve(webExtension.shutdown(reasonStr));
}
function stringReasonFromNumericReason(numericReason) {
let { BOOTSTRAP_REASONS } = AddonManagerPrivate;
return Object.keys(BOOTSTRAP_REASONS).find(
key => BOOTSTRAP_REASONS[key] == numericReason
);
}
function handleMessage(msg, sender, sendReply) {
if (!msg) {
return;
}
if (msg.funcName === "isTelemetryEnabled") {
const telemetryEnabled = getBoolPref(TELEMETRY_ENABLED_PREF);
sendReply({type: "success", value: telemetryEnabled});
} else if (msg.funcName === "isUploadDisabled") {
const isESR = AppConstants.MOZ_UPDATE_CHANNEL === "esr";
const uploadDisabled = getBoolPref(UPLOAD_DISABLED_PREF);
sendReply({type: "success", value: uploadDisabled || isESR});
} else if (msg.funcName === "isHistoryEnabled") {
const historyEnabled = getBoolPref(HISTORY_ENABLED_PREF);
sendReply({type: "success", value: historyEnabled});
} else if (msg.funcName === "incrementCount") {
const allowedScalars = ["download", "upload", "copy"];
const scalar = msg.args && msg.args[0] && msg.args[0].scalar;
if (!allowedScalars.includes(scalar)) {
sendReply({type: "error", name: `incrementCount passed an unrecognized scalar ${scalar}`});
} else {
Services.telemetry.scalarAdd(`screenshots.${scalar}`, 1);
sendReply({type: "success", value: true});
}
}
}

Просмотреть файл

@ -19,6 +19,8 @@ window.inlineSelectionCss = `
transition: background 150ms cubic-bezier(0.07, 0.95, 0, 1), border 150ms cubic-bezier(0.07, 0.95, 0, 1);
user-select: none;
white-space: nowrap; }
.button.hidden, .hidden.highlight-button-cancel, .hidden.highlight-button-save, .hidden.highlight-button-download, .hidden.highlight-button-copy, .hidden.preview-button-save {
display: none; }
.button.small, .small.highlight-button-cancel, .small.highlight-button-save, .small.highlight-button-download, .small.highlight-button-copy, .small.preview-button-save {
height: 32px;
line-height: 32px;
@ -92,27 +94,15 @@ window.inlineSelectionCss = `
background-color: #ededf0; }
.button.edit:active, .edit.highlight-button-cancel:active, .edit.highlight-button-save:active, .edit.highlight-button-download:active, .edit.highlight-button-copy:active, .edit.preview-button-save:active {
background-color: #dedede; }
.button.flag, .flag.highlight-button-cancel, .flag.highlight-button-save, .flag.highlight-button-download, .flag.highlight-button-copy, .flag.preview-button-save {
background-image: url("../img/icon-flag.svg"); }
.button.flag:hover, .flag.highlight-button-cancel:hover, .flag.highlight-button-save:hover, .flag.highlight-button-download:hover, .flag.highlight-button-copy:hover, .flag.preview-button-save:hover {
background-color: #ededf0; }
.button.flag:active, .flag.highlight-button-cancel:active, .flag.highlight-button-save:active, .flag.highlight-button-download:active, .flag.highlight-button-copy:active, .flag.preview-button-save:active {
background-color: #dedede; }
.inverse-color-scheme {
background: #38383d;
color: #f9f9fa; }
.inverse-color-scheme a {
color: #e1e1e6; }
.default-color-scheme {
.app-body {
background: #f9f9fa;
color: #38383d; }
.default-color-scheme a {
color: #009ec0; }
.app-body a {
color: #0a84ff; }
.highlight-color-scheme {
background: #009ec0;
background: #0a84ff;
color: #fff; }
.highlight-color-scheme a {
color: #fff;
@ -128,12 +118,12 @@ window.inlineSelectionCss = `
text-decoration: underline; }
.button.primary, .primary.highlight-button-cancel, .highlight-button-save, .primary.highlight-button-download, .primary.highlight-button-copy, .preview-button-save {
background-color: #009ec0;
background-color: #0a84ff;
color: #fff; }
.button.primary:hover, .primary.highlight-button-cancel:hover, .highlight-button-save:hover, .primary.highlight-button-download:hover, .primary.highlight-button-copy:hover, .preview-button-save:hover, .button.primary:focus, .primary.highlight-button-cancel:focus, .highlight-button-save:focus, .primary.highlight-button-download:focus, .primary.highlight-button-copy:focus, .preview-button-save:focus {
background-color: #00819c; }
background-color: #0072e5; }
.button.primary:active, .primary.highlight-button-cancel:active, .highlight-button-save:active, .primary.highlight-button-download:active, .primary.highlight-button-copy:active, .preview-button-save:active {
background-color: #006c83; }
background-color: #0065cc; }
.button.secondary, .highlight-button-cancel, .secondary.highlight-button-save, .highlight-button-download, .highlight-button-copy, .secondary.preview-button-save {
background-color: #f9f9fa;
@ -160,21 +150,19 @@ window.inlineSelectionCss = `
background: #a11910; }
.subtitle-link {
color: #009ec0; }
color: #0a84ff; }
.loader {
background: #2e2d30;
background: rgba(12, 12, 13, 0.2);
border-radius: 2px;
height: 4px;
overflow: hidden;
position: relative;
width: 200px; }
#shot-index .loader {
background-color: #dedede; }
.loader-inner {
animation: bounce infinite alternate 1250ms cubic-bezier(0.7, 0, 0.3, 1);
background: #04d1e6;
background: #45a1ff;
border-radius: 2px;
height: 4px;
transform: translateX(-40px);
@ -400,6 +388,14 @@ window.inlineSelectionCss = `
background-repeat: no-repeat;
height: 16px;
width: 16px; }
.notice.middle {
display: none;
top: calc(50% - 21px); }
.preview-button-save:active ~ .notice.middle,
.preview-button-save:focus ~ .notice.middle,
.preview-button-save:hover ~ .notice.middle {
display: block; }
.notice-tooltip {
background: #fff;

Просмотреть файл

@ -1,18 +1,16 @@
/* Created from build/server/static/css/onboarding.css */
window.onboardingCss = `
.loader {
background: #2e2d30;
background: rgba(12, 12, 13, 0.2);
border-radius: 2px;
height: 4px;
overflow: hidden;
position: relative;
width: 200px; }
#shot-index .loader {
background-color: #dedede; }
.loader-inner {
animation: bounce infinite alternate 1250ms cubic-bezier(0.7, 0, 0.3, 1);
background: #04d1e6;
background: #45a1ff;
border-radius: 2px;
height: 4px;
transform: translateX(-40px);
@ -162,14 +160,16 @@ body {
.slide-2,
.slide-3,
.slide-4,
.slide-5 {
.slide-5,
.slide-6 {
display: none; }
.active-slide-1 .slide-1,
.active-slide-2 .slide-2,
.active-slide-3 .slide-3,
.active-slide-4 .slide-4,
.active-slide-5 .slide-5 {
.active-slide-5 .slide-5,
.active-slide-6 .slide-6 {
display: flex; }
#slide-status-container {
@ -197,7 +197,8 @@ body {
.active-slide-2 .goto-slide-2,
.active-slide-3 .goto-slide-3,
.active-slide-4 .goto-slide-4,
.active-slide-5 .goto-slide-5 {
.active-slide-5 .goto-slide-5,
.active-slide-6 .goto-slide-6 {
opacity: 1;
transform: scale(1.1); }
@ -281,14 +282,14 @@ body {
opacity: 1; }
.active-slide-1 #prev,
.active-slide-5 #next {
.active-slide-6 #next {
display: none; }
#done {
background-image: url("MOZ_EXTENSION/icons/done.svg");
display: none; }
.active-slide-5 #done {
.active-slide-6 #done {
display: inline-block; }
/* for smaller screen sizes */

Просмотреть файл

@ -1,4 +1,4 @@
/* Created from addon/webextension/onboarding/slides.html */
/* Created from webextension/onboarding/slides.html */
window.onboardingHtml = `
<!DOCTYPE html>
<html>
@ -10,7 +10,7 @@ window.onboardingHtml = `
<body>
<div id="slide-overlay">
<!-- The current slide is set by having .active-slide-1, .active-slide-2, etc on #slide element: -->
<div id="slide-container" data-number-of-slides="5" class="active-slide-1">
<div id="slide-container" data-number-of-slides="6" class="active-slide-1">
<div class="slide slide-1">
<!-- Note: all images must be listed in manifest.json.template under web_accessible_resources -->
<div class="slide-image" style="background-image: url('MOZ_EXTENSION/icons/onboarding-1.png');"></div>
@ -50,6 +50,13 @@ window.onboardingHtml = `
<p data-l10n-id="tourBodyDownloadUpload"></p>
</div>
</div>
<div class="slide slide-6">
<div class="slide-image" style="background-image: url('MOZ_EXTENSION/icons/onboarding-6.png');"></div>
<div class="slide-content">
<h1 data-l10n-id="tourHeaderAccounts"></h1>
<p data-l10n-id="tourBodyAccounts"></p>
</div>
</div>
<!-- Clickable elements should be buttons for accessibility -->
<button id="skip" data-l10n-id="tourSkip" tabindex=1>Skip</button>
@ -62,6 +69,7 @@ window.onboardingHtml = `
<button class="goto-slide goto-slide-3" data-number="3" tabindex=6></button>
<button class="goto-slide goto-slide-4" data-number="4" tabindex=7></button>
<button class="goto-slide goto-slide-5" data-number="5" tabindex=8></button>
<button class="goto-slide goto-slide-6" data-number="6" tabindex=9></button>
</div>
<!-- FIXME: Need to put in privacy / etc links -->
</div>

Просмотреть файл

@ -191,7 +191,6 @@ class AbstractShot {
this.docTitle = attrs.docTitle || null;
this.userTitle = attrs.userTitle || null;
this.createdDate = attrs.createdDate || Date.now();
this.favicon = attrs.favicon || null;
this.siteName = attrs.siteName || null;
this.images = [];
if (attrs.images) {
@ -203,6 +202,7 @@ class AbstractShot {
this.documentSize = attrs.documentSize || null;
this.thumbnail = attrs.thumbnail || null;
this.abTests = attrs.abTests || null;
this.firefoxChannel = attrs.firefoxChannel || null;
this._clips = {};
if (attrs.clips) {
for (const clipId in attrs.clips) {
@ -458,15 +458,6 @@ class AbstractShot {
this._createdDate = val;
}
get favicon() {
return this._favicon;
}
set favicon(val) {
// We set the favicon with tabs.Tab.faviConUrl, which is a full URL.
val = val || null;
this._favicon = val;
}
clipNames() {
const names = Object.getOwnPropertyNames(this._clips);
names.sort(function(a, b) {
@ -563,24 +554,35 @@ class AbstractShot {
this._abTests = val;
}
get firefoxChannel() {
return this._firefoxChannel;
}
set firefoxChannel(val) {
if (val === null || val === undefined) {
this._firefoxChannel = null;
return;
}
assert(typeof val === "string", "firefoxChannel should be a string, not:", typeof val);
this._firefoxChannel = val;
}
}
AbstractShot.prototype.REGULAR_ATTRS = (`
origin fullUrl docTitle userTitle createdDate favicon images
origin fullUrl docTitle userTitle createdDate images
siteName openGraph twitterCard documentSize
thumbnail abTests
thumbnail abTests firefoxChannel
`).split(/\s+/g);
// Attributes that will be accepted in the constructor, but ignored/dropped
AbstractShot.prototype.DEPRECATED_ATTRS = (`
microdata history ogTitle createdDevice head body htmlAttrs bodyAttrs headAttrs
readable hashtags comments showPage isPublic resources deviceId url
fullScreenThumbnail
fullScreenThumbnail favicon
`).split(/\s+/g);
AbstractShot.prototype.RECALL_ATTRS = (`
url docTitle userTitle createdDate favicon
openGraph twitterCard images thumbnail
url docTitle userTitle createdDate openGraph twitterCard images thumbnail
`).split(/\s+/g);
AbstractShot.prototype._OPENGRAPH_PROPERTIES = (`

Просмотреть файл

@ -1,4 +1,4 @@
this.thumbnailGenerator = (function () {let exports={}; // This is used in addon/webextension/background/takeshot.js,
this.thumbnailGenerator = (function () {let exports={}; // This is used in webextension/background/takeshot.js,
// server/src/pages/shot/controller.js, and
// server/scr/pages/shotindex/view.js. It is used in a browser
// environment.

Просмотреть файл

@ -0,0 +1,115 @@
/* globals browser, AppConstants, CustomizableUI, ExtensionCommon, Services, ExtensionAPI */
"use strict";
ChromeUtils.defineModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
ChromeUtils.defineModuleGetter(this, "CustomizableUI",
"resource:///modules/CustomizableUI.jsm");
ChromeUtils.defineModuleGetter(this, "ExtensionCommon",
"resource://gre/modules/ExtensionCommon.jsm");
ChromeUtils.defineModuleGetter(this, "PageActions",
"resource:///modules/PageActions.jsm");
ChromeUtils.defineModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
const LibraryButton = {
ITEM_ID: "appMenu-library-screenshots",
init(webExtension) {
this._initialized = true;
const permissionPages = [...webExtension.permissions].filter(p => (/^https?:\/\//i).test(p));
if (permissionPages.length > 1) {
Cu.reportError(new Error("Should not have more than 1 permission page, but got: " + JSON.stringify(permissionPages)));
}
this.PAGE_TO_OPEN = permissionPages.length === 1 ? permissionPages[0].replace(/\*$/, "") : "https://screenshots.firefox.com/";
this.PAGE_TO_OPEN += "shots";
this.ICON_URL = webExtension.getURL("icons/icon-v2.svg");
this.LABEL = webExtension.localizeMessage("libraryLabel");
CustomizableUI.addListener(this);
for (const win of CustomizableUI.windows) {
this.onWindowOpened(win);
}
},
uninit() {
if (!this._initialized) {
return;
}
for (const win of CustomizableUI.windows) {
const item = win.document.getElementById(this.ITEM_ID);
if (item) {
item.remove();
}
}
CustomizableUI.removeListener(this);
this._initialized = false;
},
onWindowOpened(win) {
const libraryViewInsertionPoint = win.document.getElementById("appMenu-library-remotetabs-button");
// If the library view doesn't exist (on non-photon builds, for instance),
// this will be null, and we bail out early.
if (!libraryViewInsertionPoint) {
return;
}
const parent = libraryViewInsertionPoint.parentNode;
const {nextSibling} = libraryViewInsertionPoint;
const item = win.document.createElement("toolbarbutton");
item.className = "subviewbutton subviewbutton-iconic";
item.addEventListener("command", () => win.openWebLinkIn(this.PAGE_TO_OPEN, "tab"));
item.id = this.ITEM_ID;
const iconURL = this.ICON_URL;
item.setAttribute("image", iconURL);
item.setAttribute("label", this.LABEL);
parent.insertBefore(item, nextSibling);
},
};
this.screenshots = class extends ExtensionAPI {
getAPI(context) {
const {extension} = context;
return {
experiments: {
screenshots: {
// If you are checking for 'nightly', also check for 'nightly-try'.
//
// Otherwise, just use the standard builds, but be aware of the many
// non-standard options that also exist (as of August 2018).
//
// Standard builds:
// 'esr' - ESR channel
// 'release' - release channel
// 'beta' - beta channel
// 'nightly' - nightly channel
// Non-standard / deprecated builds:
// 'aurora' - deprecated aurora channel (still observed in dxr)
// 'default' - local builds from source
// 'nightly-try' - nightly Try builds (QA may occasionally need to test with these)
getUpdateChannel() {
return AppConstants.MOZ_UPDATE_CHANNEL;
},
isHistoryEnabled() {
return Services.prefs.getBoolPref("places.history.enabled", true);
},
isUploadDisabled() {
return Services.prefs.getBoolPref("extensions.screenshots.upload-disabled", false);
},
initLibraryButton() {
context.callOnClose({
close: () => {
try {
LibraryButton.uninit();
} catch (ex) {
Services.console.logStringMessage("Firefox Screenshots LibraryButton shutdown error: ", ex);
}
},
});
return LibraryButton.init(extension);
},
},
},
};
}
};

Просмотреть файл

@ -0,0 +1,36 @@
[
{
"namespace": "experiments.screenshots",
"description": "Firefox Screenshots internal API",
"functions": [
{
"name": "getUpdateChannel",
"type": "function",
"description": "Returns the Firefox channel (AppConstants.MOZ_UPDATE_CHANNEL)",
"parameters": [],
"async": true
},
{
"name": "isHistoryEnabled",
"type": "function",
"description": "Returns the value of the 'places.history.enabled' preference",
"parameters": [],
"async": true
},
{
"name": "isUploadDisabled",
"type": "function",
"description": "Returns the value of the 'extensions.screenshots.upload-disabled' preference",
"parameters": [],
"async": true
},
{
"name": "initLibraryButton",
"type": "function",
"description": "Initializes the Photon-based Library menu item for Screenshots",
"parameters": [],
"async": true
}
]
}
]

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 271 B

После

Ширина:  |  Высота:  |  Размер: 271 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 271 B

После

Ширина:  |  Высота:  |  Размер: 271 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 296 B

После

Ширина:  |  Высота:  |  Размер: 296 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 601 B

После

Ширина:  |  Высота:  |  Размер: 601 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 415 B

После

Ширина:  |  Высота:  |  Размер: 415 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 378 B

После

Ширина:  |  Высота:  |  Размер: 378 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 240 B

После

Ширина:  |  Высота:  |  Размер: 240 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 346 B

После

Ширина:  |  Высота:  |  Размер: 346 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 522 B

После

Ширина:  |  Высота:  |  Размер: 522 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 595 B

После

Ширина:  |  Высота:  |  Размер: 595 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 657 B

После

Ширина:  |  Высота:  |  Размер: 657 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 1001 B

После

Ширина:  |  Высота:  |  Размер: 1001 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 1.1 KiB

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 345 B

После

Ширина:  |  Высота:  |  Размер: 345 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 328 B

После

Ширина:  |  Высота:  |  Размер: 328 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 767 B

После

Ширина:  |  Высота:  |  Размер: 767 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 27 KiB

После

Ширина:  |  Высота:  |  Размер: 27 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 40 KiB

После

Ширина:  |  Высота:  |  Размер: 40 KiB

Двоичные данные
browser/extensions/screenshots/icons/onboarding-3.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 70 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 34 KiB

После

Ширина:  |  Высота:  |  Размер: 34 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 15 KiB

После

Ширина:  |  Высота:  |  Размер: 15 KiB

Двоичные данные
browser/extensions/screenshots/icons/onboarding-6.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 22 KiB

Просмотреть файл

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>screenshots@mozilla.org</em:id>
<em:name>Firefox Screenshots</em:name>
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!--Firefox-->
<em:minVersion>57.0a1</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
<em:type>2</em:type>
<em:version>33.0.0</em:version>
<em:bootstrap>true</em:bootstrap>
<em:homepageURL>https://screenshots.firefox.com/</em:homepageURL>
<em:multiprocessCompatible>true</em:multiprocessCompatible>
</Description>
</RDF>

Просмотреть файл

@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "Firefox Screenshots",
"version": "33.0.0",
"version": "35.0.0",
"description": "__MSG_addonDescription__",
"author": "__MSG_addonAuthorsList__",
"homepage_url": "https://github.com/mozilla-services/screenshots",
@ -59,6 +59,7 @@
"icons/onboarding-3.png",
"icons/onboarding-4.png",
"icons/onboarding-5.png",
"icons/onboarding-6.png",
"icons/done.svg",
"icons/icon-welcome-face-without-eyes.svg"
],
@ -71,9 +72,20 @@
"clipboardWrite",
"contextMenus",
"mozillaAddons",
"telemetry",
"<all_urls>",
"https://screenshots.firefox.com/",
"resource://pdf.js/",
"about:reader*"
]
],
"experiment_apis": {
"screenshots": {
"schema": "experiments/screenshots/schema.json",
"parent": {
"scopes": ["addon_parent"],
"script": "experiments/screenshots/api.js",
"paths": [["experiments", "screenshots"]]
}
}
}
}

Просмотреть файл

@ -5,449 +5,465 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
with Files("**"):
BUG_COMPONENT = ("Cloud Services", "Screenshots")
FINAL_TARGET_FILES.features['screenshots@mozilla.org'] += [
'bootstrap.js',
'install.rdf'
]
BUG_COMPONENT = ("Firefox", "Screenshots")
# This file list is automatically generated by Screenshots' export scripts.
# AUTOMATIC INSERTION START
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"] += [
'webextension/assertIsBlankDocument.js',
'webextension/assertIsTrusted.js',
'webextension/blank.html',
'webextension/blobConverters.js',
'webextension/catcher.js',
'webextension/clipboard.js',
'webextension/domainFromUrl.js',
'webextension/log.js',
'webextension/makeUuid.js',
'webextension/manifest.json',
'webextension/randomString.js',
'webextension/sitehelper.js'
FINAL_TARGET_FILES.features['screenshots@mozilla.org'] += [
'assertIsBlankDocument.js',
'assertIsTrusted.js',
'blank.html',
'blobConverters.js',
'catcher.js',
'clipboard.js',
'domainFromUrl.js',
'log.js',
'makeUuid.js',
'manifest.json',
'moz.build',
'randomString.js',
'sitehelper.js'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ach"] += [
'webextension/_locales/ach/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ach"] += [
'_locales/ach/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ar"] += [
'webextension/_locales/ar/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ar"] += [
'_locales/ar/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ast"] += [
'webextension/_locales/ast/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ast"] += [
'_locales/ast/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["az"] += [
'webextension/_locales/az/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["az"] += [
'_locales/az/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["be"] += [
'webextension/_locales/be/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["be"] += [
'_locales/be/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["bg"] += [
'webextension/_locales/bg/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["bg"] += [
'_locales/bg/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["bn_BD"] += [
'webextension/_locales/bn_BD/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["bn_BD"] += [
'_locales/bn_BD/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["br"] += [
'webextension/_locales/br/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["br"] += [
'_locales/br/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["bs"] += [
'webextension/_locales/bs/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["bs"] += [
'_locales/bs/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ca"] += [
'webextension/_locales/ca/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ca"] += [
'_locales/ca/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["cak"] += [
'webextension/_locales/cak/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["cak"] += [
'_locales/cak/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["crh"] += [
'webextension/_locales/crh/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["crh"] += [
'_locales/crh/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["cs"] += [
'webextension/_locales/cs/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["cs"] += [
'_locales/cs/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["cy"] += [
'webextension/_locales/cy/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["cy"] += [
'_locales/cy/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["da"] += [
'webextension/_locales/da/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["da"] += [
'_locales/da/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["de"] += [
'webextension/_locales/de/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["de"] += [
'_locales/de/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["dsb"] += [
'webextension/_locales/dsb/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["dsb"] += [
'_locales/dsb/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["el"] += [
'webextension/_locales/el/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["el"] += [
'_locales/el/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["en_GB"] += [
'webextension/_locales/en_GB/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["en_CA"] += [
'_locales/en_CA/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["en_US"] += [
'webextension/_locales/en_US/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["en_GB"] += [
'_locales/en_GB/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["eo"] += [
'webextension/_locales/eo/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["en_US"] += [
'_locales/en_US/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["es_AR"] += [
'webextension/_locales/es_AR/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["eo"] += [
'_locales/eo/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["es_CL"] += [
'webextension/_locales/es_CL/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["es_AR"] += [
'_locales/es_AR/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["es_ES"] += [
'webextension/_locales/es_ES/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["es_CL"] += [
'_locales/es_CL/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["es_MX"] += [
'webextension/_locales/es_MX/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["es_ES"] += [
'_locales/es_ES/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["et"] += [
'webextension/_locales/et/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["es_MX"] += [
'_locales/es_MX/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["eu"] += [
'webextension/_locales/eu/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["et"] += [
'_locales/et/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["fa"] += [
'webextension/_locales/fa/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["eu"] += [
'_locales/eu/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ff"] += [
'webextension/_locales/ff/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["fa"] += [
'_locales/fa/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["fi"] += [
'webextension/_locales/fi/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ff"] += [
'_locales/ff/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["fr"] += [
'webextension/_locales/fr/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["fi"] += [
'_locales/fi/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["fy_NL"] += [
'webextension/_locales/fy_NL/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["fr"] += [
'_locales/fr/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ga_IE"] += [
'webextension/_locales/ga_IE/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["fy_NL"] += [
'_locales/fy_NL/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["gd"] += [
'webextension/_locales/gd/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ga_IE"] += [
'_locales/ga_IE/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["gl"] += [
'webextension/_locales/gl/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["gd"] += [
'_locales/gd/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["gn"] += [
'webextension/_locales/gn/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["gl"] += [
'_locales/gl/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["gu_IN"] += [
'webextension/_locales/gu_IN/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["gn"] += [
'_locales/gn/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["he"] += [
'webextension/_locales/he/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["gu_IN"] += [
'_locales/gu_IN/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["hi_IN"] += [
'webextension/_locales/hi_IN/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["he"] += [
'_locales/he/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["hr"] += [
'webextension/_locales/hr/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["hi_IN"] += [
'_locales/hi_IN/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["hsb"] += [
'webextension/_locales/hsb/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["hr"] += [
'_locales/hr/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["hu"] += [
'webextension/_locales/hu/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["hsb"] += [
'_locales/hsb/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["hy_AM"] += [
'webextension/_locales/hy_AM/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["hu"] += [
'_locales/hu/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ia"] += [
'webextension/_locales/ia/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["hy_AM"] += [
'_locales/hy_AM/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["id"] += [
'webextension/_locales/id/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ia"] += [
'_locales/ia/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["it"] += [
'webextension/_locales/it/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["id"] += [
'_locales/id/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ja"] += [
'webextension/_locales/ja/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["it"] += [
'_locales/it/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ka"] += [
'webextension/_locales/ka/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ja"] += [
'_locales/ja/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["kab"] += [
'webextension/_locales/kab/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ka"] += [
'_locales/ka/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["kk"] += [
'webextension/_locales/kk/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["kab"] += [
'_locales/kab/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["km"] += [
'webextension/_locales/km/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["kk"] += [
'_locales/kk/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["kn"] += [
'webextension/_locales/kn/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["km"] += [
'_locales/km/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ko"] += [
'webextension/_locales/ko/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["kn"] += [
'_locales/kn/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["lij"] += [
'webextension/_locales/lij/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ko"] += [
'_locales/ko/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["lo"] += [
'webextension/_locales/lo/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["lij"] += [
'_locales/lij/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["lt"] += [
'webextension/_locales/lt/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["lo"] += [
'_locales/lo/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["mai"] += [
'webextension/_locales/mai/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["lt"] += [
'_locales/lt/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["mk"] += [
'webextension/_locales/mk/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["mai"] += [
'_locales/mai/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ml"] += [
'webextension/_locales/ml/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["mk"] += [
'_locales/mk/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["mn"] += [
'webextension/_locales/mn/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ml"] += [
'_locales/ml/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["mr"] += [
'webextension/_locales/mr/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["mn"] += [
'_locales/mn/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ms"] += [
'webextension/_locales/ms/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["mr"] += [
'_locales/mr/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["my"] += [
'webextension/_locales/my/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ms"] += [
'_locales/ms/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["nb_NO"] += [
'webextension/_locales/nb_NO/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["my"] += [
'_locales/my/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ne_NP"] += [
'webextension/_locales/ne_NP/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["nb_NO"] += [
'_locales/nb_NO/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["nl"] += [
'webextension/_locales/nl/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ne_NP"] += [
'_locales/ne_NP/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["nn_NO"] += [
'webextension/_locales/nn_NO/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["nl"] += [
'_locales/nl/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["pa_IN"] += [
'webextension/_locales/pa_IN/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["nn_NO"] += [
'_locales/nn_NO/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["pl"] += [
'webextension/_locales/pl/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["pa_IN"] += [
'_locales/pa_IN/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["pt_BR"] += [
'webextension/_locales/pt_BR/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["pl"] += [
'_locales/pl/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["pt_PT"] += [
'webextension/_locales/pt_PT/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["pt_BR"] += [
'_locales/pt_BR/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["rm"] += [
'webextension/_locales/rm/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["pt_PT"] += [
'_locales/pt_PT/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ro"] += [
'webextension/_locales/ro/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["rm"] += [
'_locales/rm/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ru"] += [
'webextension/_locales/ru/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ro"] += [
'_locales/ro/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["sk"] += [
'webextension/_locales/sk/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ru"] += [
'_locales/ru/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["sl"] += [
'webextension/_locales/sl/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["si"] += [
'_locales/si/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["sq"] += [
'webextension/_locales/sq/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["sk"] += [
'_locales/sk/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["sr"] += [
'webextension/_locales/sr/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["sl"] += [
'_locales/sl/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["sv_SE"] += [
'webextension/_locales/sv_SE/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["sq"] += [
'_locales/sq/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ta"] += [
'webextension/_locales/ta/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["sr"] += [
'_locales/sr/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["te"] += [
'webextension/_locales/te/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["sv_SE"] += [
'_locales/sv_SE/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["th"] += [
'webextension/_locales/th/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ta"] += [
'_locales/ta/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["tl"] += [
'webextension/_locales/tl/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["te"] += [
'_locales/te/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["tr"] += [
'webextension/_locales/tr/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["th"] += [
'_locales/th/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["uk"] += [
'webextension/_locales/uk/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["tl"] += [
'_locales/tl/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ur"] += [
'webextension/_locales/ur/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["tr"] += [
'_locales/tr/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["uz"] += [
'webextension/_locales/uz/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["uk"] += [
'_locales/uk/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["vi"] += [
'webextension/_locales/vi/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["ur"] += [
'_locales/ur/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["zh_CN"] += [
'webextension/_locales/zh_CN/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["uz"] += [
'_locales/uz/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["zh_TW"] += [
'webextension/_locales/zh_TW/messages.json'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["vi"] += [
'_locales/vi/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["background"] += [
'webextension/background/analytics.js',
'webextension/background/auth.js',
'webextension/background/communication.js',
'webextension/background/deviceInfo.js',
'webextension/background/main.js',
'webextension/background/selectorLoader.js',
'webextension/background/senderror.js',
'webextension/background/startBackground.js',
'webextension/background/takeshot.js'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["zh_CN"] += [
'_locales/zh_CN/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["build"] += [
'webextension/build/buildSettings.js',
'webextension/build/inlineSelectionCss.js',
'webextension/build/onboardingCss.js',
'webextension/build/onboardingHtml.js',
'webextension/build/raven.js',
'webextension/build/selection.js',
'webextension/build/shot.js',
'webextension/build/thumbnailGenerator.js'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["_locales"]["zh_TW"] += [
'_locales/zh_TW/messages.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["icons"] += [
'webextension/icons/back-highlight.svg',
'webextension/icons/back.svg',
'webextension/icons/cancel.svg',
'webextension/icons/cloud.svg',
'webextension/icons/copied-notification.svg',
'webextension/icons/copy.svg',
'webextension/icons/done.svg',
'webextension/icons/download.svg',
'webextension/icons/help-16.svg',
'webextension/icons/icon-highlight-32-v2.svg',
'webextension/icons/icon-v2.svg',
'webextension/icons/icon-welcome-face-without-eyes.svg',
'webextension/icons/menu-fullpage.svg',
'webextension/icons/menu-myshot-white.svg',
'webextension/icons/menu-myshot.svg',
'webextension/icons/menu-visible.svg',
'webextension/icons/onboarding-1.png',
'webextension/icons/onboarding-2.png',
'webextension/icons/onboarding-3.png',
'webextension/icons/onboarding-4.png',
'webextension/icons/onboarding-5.png'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["background"] += [
'background/analytics.js',
'background/auth.js',
'background/communication.js',
'background/deviceInfo.js',
'background/main.js',
'background/selectorLoader.js',
'background/senderror.js',
'background/startBackground.js',
'background/takeshot.js'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["onboarding"] += [
'webextension/onboarding/slides.html',
'webextension/onboarding/slides.js'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["build"] += [
'build/buildSettings.js',
'build/inlineSelectionCss.js',
'build/onboardingCss.js',
'build/onboardingHtml.js',
'build/raven.js',
'build/selection.js',
'build/shot.js',
'build/thumbnailGenerator.js'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["selector"] += [
'webextension/selector/callBackground.js',
'webextension/selector/documentMetadata.js',
'webextension/selector/shooter.js',
'webextension/selector/ui.js',
'webextension/selector/uicontrol.js',
'webextension/selector/util.js'
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["experiments"]["screenshots"] += [
'experiments/screenshots/api.js',
'experiments/screenshots/schema.json'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["icons"] += [
'icons/back-highlight.svg',
'icons/back.svg',
'icons/cancel.svg',
'icons/cloud.svg',
'icons/copied-notification.svg',
'icons/copy.svg',
'icons/done.svg',
'icons/download.svg',
'icons/help-16.svg',
'icons/icon-highlight-32-v2.svg',
'icons/icon-v2.svg',
'icons/icon-welcome-face-without-eyes.svg',
'icons/menu-fullpage.svg',
'icons/menu-myshot-white.svg',
'icons/menu-myshot.svg',
'icons/menu-visible.svg',
'icons/onboarding-1.png',
'icons/onboarding-2.png',
'icons/onboarding-3.png',
'icons/onboarding-4.png',
'icons/onboarding-5.png',
'icons/onboarding-6.png'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["onboarding"] += [
'onboarding/slides.html',
'onboarding/slides.js'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["selector"] += [
'selector/callBackground.js',
'selector/documentMetadata.js',
'selector/shooter.js',
'selector/ui.js',
'selector/uicontrol.js',
'selector/util.js'
]
FINAL_TARGET_FILES.features['screenshots@mozilla.org']["test"]["browser"] += [
'test/browser/.eslintrc.yml',
'test/browser/browser.ini',
'test/browser/browser_screenshots_ui_check.js'
]
# AUTOMATIC INSERTION END

Просмотреть файл

@ -8,7 +8,7 @@
<body>
<div id="slide-overlay">
<!-- The current slide is set by having .active-slide-1, .active-slide-2, etc on #slide element: -->
<div id="slide-container" data-number-of-slides="5" class="active-slide-1">
<div id="slide-container" data-number-of-slides="6" class="active-slide-1">
<div class="slide slide-1">
<!-- Note: all images must be listed in manifest.json.template under web_accessible_resources -->
<div class="slide-image" style="background-image: url('MOZ_EXTENSION/icons/onboarding-1.png');"></div>
@ -48,6 +48,13 @@
<p data-l10n-id="tourBodyDownloadUpload"></p>
</div>
</div>
<div class="slide slide-6">
<div class="slide-image" style="background-image: url('MOZ_EXTENSION/icons/onboarding-6.png');"></div>
<div class="slide-content">
<h1 data-l10n-id="tourHeaderAccounts"></h1>
<p data-l10n-id="tourBodyAccounts"></p>
</div>
</div>
<!-- Clickable elements should be buttons for accessibility -->
<button id="skip" data-l10n-id="tourSkip" tabindex=1>Skip</button>
@ -60,6 +67,7 @@
<button class="goto-slide goto-slide-3" data-number="3" tabindex=6></button>
<button class="goto-slide goto-slide-4" data-number="4" tabindex=7></button>
<button class="goto-slide goto-slide-5" data-number="5" tabindex=8></button>
<button class="goto-slide goto-slide-6" data-number="6" tabindex=9></button>
</div>
<!-- FIXME: Need to put in privacy / etc links -->
</div>

Просмотреть файл

@ -30,6 +30,7 @@ this.slides = (function() {
iframe.style.top = "0";
iframe.style.left = "0";
iframe.style.margin = "0";
iframe.style.backgroundColor = "transparent";
iframe.scrolling = "no";
updateIframeSize();
let html = onboardingHtml.replace("<style></style>", `<style>${onboardingCss}</style>`);

Просмотреть файл

@ -3,12 +3,12 @@
this.documentMetadata = (function() {
function findSiteName() {
let el = document.querySelector("meta[property='og:site_name']");
let el = document.querySelector("meta[property~='og:site_name'][content]");
if (el) {
return el.getAttribute("content");
}
// nytimes.com uses this property:
el = document.querySelector("meta[name='cre']");
el = document.querySelector("meta[name='cre'][content]");
if (el) {
return el.getAttribute("content");
}
@ -29,7 +29,7 @@ this.documentMetadata = (function() {
profile:first_name profile:last_name profile:username profile:gender
`.split(/\s+/g);
for (const prop of openGraphProperties) {
let elems = document.querySelectorAll(`meta[property='og:${prop}']`);
let elems = document.querySelectorAll(`meta[property~='og:${prop}'][content]`);
if (forceSingle.includes(prop) && elems.length > 1) {
elems = [elems[0]];
}
@ -63,7 +63,7 @@ this.documentMetadata = (function() {
player player:width player:height player:stream player:stream:content_type
`.split(/\s+/g);
for (const prop of properties) {
const elem = document.querySelector(`meta[name='twitter:${prop}']`);
const elem = document.querySelector(`meta[name='twitter:${prop}'][content]`);
if (elem) {
const value = elem.getAttribute("content");
if (value) {

Просмотреть файл

@ -8,6 +8,7 @@ this.shooter = (function() { // eslint-disable-line no-unused-vars
const { AbstractShot } = shot;
const RANDOM_STRING_LENGTH = 16;
const MAX_CANVAS_DIMENSION = 32767;
let backend;
let shotObject;
let supportsDrawWindow;
@ -40,10 +41,12 @@ this.shooter = (function() { // eslint-disable-line no-unused-vars
})();
function captureToCanvas(selectedPos, captureType) {
const height = selectedPos.bottom - selectedPos.top;
const width = selectedPos.right - selectedPos.left;
let height = selectedPos.bottom - selectedPos.top;
let width = selectedPos.right - selectedPos.left;
const canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
const ctx = canvas.getContext("2d");
// Scale the canvas for high-density displays, except for full-page shots.
let expand = window.devicePixelRatio !== 1;
if (captureType === "fullPage" || captureType === "fullPageTruncated") {
expand = false;
@ -56,6 +59,19 @@ this.shooter = (function() { // eslint-disable-line no-unused-vars
if (expand) {
ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
}
// Double-check canvas width and height are within the canvas pixel limit.
// If the canvas dimensions are too great, crop the canvas and also crop
// the selection by a devicePixelRatio-scaled amount.
if (canvas.width > MAX_CANVAS_DIMENSION) {
canvas.width = MAX_CANVAS_DIMENSION;
width = expand ? Math.floor(canvas.width / window.devicePixelRatio) : canvas.width;
}
if (canvas.height > MAX_CANVAS_DIMENSION) {
canvas.height = MAX_CANVAS_DIMENSION;
height = expand ? Math.floor(canvas.height / window.devicePixelRatio) : canvas.height;
}
ui.iframe.hide();
ctx.drawWindow(window, selectedPos.left, selectedPos.top, width, height, "#fff");
return canvas;

Просмотреть файл

@ -140,6 +140,8 @@ this.ui = (function() { // eslint-disable-line no-unused-vars
this.element.id = "firefox-screenshots-selection-iframe";
this.element.style.display = "none";
this.element.style.setProperty("position", "absolute", "important");
this.element.style.setProperty("background-color", "transparent");
this.element.setAttribute("role", "dialog");
this.updateElementSize();
this.element.addEventListener("load", watchFunction(() => {
this.document = this.element.contentDocument;
@ -274,8 +276,10 @@ this.ui = (function() { // eslint-disable-line no-unused-vars
this.element = initializeIframe();
this.element.id = "firefox-screenshots-preselection-iframe";
this.element.style.setProperty("position", "fixed", "important");
this.element.style.setProperty("background-color", "transparent");
this.element.style.width = "100%";
this.element.style.height = "100%";
this.element.setAttribute("role", "dialog");
this.element.addEventListener("load", watchFunction(() => {
this.document = this.element.contentDocument;
assertIsBlankDocument(this.document);
@ -297,11 +301,11 @@ this.ui = (function() { // eslint-disable-line no-unused-vars
<button class="cancel-shot">${browser.i18n.getMessage("cancelScreenshot")}</button>
<div class="myshots-all-buttons-container">
${isDownloadOnly() ? "" : `
<button class="myshots-button" tabindex="1" data-l10n-id="myShotsLink"></button>
<button class="myshots-button" tabindex="3" data-l10n-id="myShotsLink"></button>
<div class="spacer"></div>
`}
<button class="visible" tabindex="2" data-l10n-id="saveScreenshotVisibleArea"></button>
<button class="full-page" tabindex="3" data-l10n-id="saveScreenshotFullPage"></button>
<button class="full-page" tabindex="1" data-l10n-id="saveScreenshotFullPage"></button>
</div>
</div>
</div>
@ -385,8 +389,10 @@ this.ui = (function() { // eslint-disable-line no-unused-vars
this.element.id = "firefox-screenshots-preview-iframe";
this.element.style.display = "none";
this.element.style.setProperty("position", "fixed", "important");
this.element.style.setProperty("background-color", "transparent");
this.element.style.height = "100%";
this.element.style.width = "100%";
this.element.setAttribute("role", "dialog");
this.element.onload = watchFunction(() => {
this.document = this.element.contentDocument;
// eslint-disable-next-line no-unsanitized/property
@ -625,7 +631,7 @@ this.ui = (function() { // eslint-disable-line no-unused-vars
this.bgTop.style.left = "0px";
this.bgTop.style.width = "100%";
this.bgBottom.style.top = `${pos.bottom}px`;
this.bgBottom.style.height = "100vh";
this.bgBottom.style.height = `calc(100vh - ${pos.bottom}px)`;
this.bgBottom.style.left = "0px";
this.bgBottom.style.width = "100%";
this.bgLeft.style.top = `${pos.top}px`;
@ -635,7 +641,7 @@ this.ui = (function() { // eslint-disable-line no-unused-vars
this.bgRight.style.top = `${pos.top}px`;
this.bgRight.style.height = `${pos.bottom - pos.top}px`;
this.bgRight.style.left = `${pos.right}px`;
this.bgRight.style.width = `${document.body.scrollWidth - pos.right}px`;
this.bgRight.style.width = `calc(100% - ${pos.right}px)`;
// the download notice is injected into an iframe that matches the document size
// in order to reposition it on scroll we need to bind an updated positioning
// function to some window events.
@ -856,8 +862,8 @@ this.ui = (function() { // eslint-disable-line no-unused-vars
this.el.appendChild(this.yEl);
iframe.document().body.appendChild(this.el);
}
this.xEl.textContent = x;
this.yEl.textContent = y;
this.xEl.textContent = Math.round(x);
this.yEl.textContent = Math.round(y);
this.el.style.top = (yPos + 12) + "px";
this.el.style.left = (xPos + 12) + "px";
},
@ -874,16 +880,15 @@ this.ui = (function() { // eslint-disable-line no-unused-vars
img.src = URL.createObjectURL(imgBlob);
iframe.document().querySelector(".preview-image").appendChild(img);
if (showCropWarning && !(isDownloadOnly())) {
const imageCroppedEl = makeEl("table", "notice");
imageCroppedEl.style.bottom = "10px";
const imageCroppedEl = makeEl("table", "notice middle");
imageCroppedEl.innerHTML = `<tbody>
<tr class="notice-wrapper">
<td class="notice-content"></td>
</tr>
</tbody>`;
const contentCell = imageCroppedEl.getElementsByTagName("td");
contentCell[0].textContent = browser.i18n.getMessage("imageCroppedWarning", buildSettings.maxImageHeight);
iframe.document().querySelector(".preview-overlay").appendChild(imageCroppedEl);
contentCell[0].textContent = browser.i18n.getMessage("imageCropPopupWarning", buildSettings.maxImageHeight);
iframe.document().querySelector(".preview-buttons").appendChild(imageCroppedEl);
}
}
};

Просмотреть файл

@ -194,16 +194,14 @@ this.uicontrol = (function() {
onClickFullPage: () => {
sendEvent("capture-full-page", "selection-button");
captureType = "fullPage";
let width = getDocumentWidth();
const width = getDocumentWidth();
if (width > MAX_PAGE_WIDTH) {
captureType = "fullPageTruncated";
}
width = Math.min(width, MAX_PAGE_WIDTH);
let height = getDocumentHeight();
const height = getDocumentHeight();
if (height > MAX_PAGE_HEIGHT) {
captureType = "fullPageTruncated";
}
height = Math.min(height, MAX_PAGE_HEIGHT);
selectedPos = new Selection(
0, 0,
width, height);
@ -211,6 +209,13 @@ this.uicontrol = (function() {
},
onSavePreview: () => {
sendEvent(`save-${captureType.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase()}`, "save-preview-button");
if (captureType === "fullPageTruncated") {
selectedPos = new Selection(
0, 0,
Math.min(selectedPos.right, MAX_PAGE_WIDTH),
Math.min(selectedPos.bottom, MAX_PAGE_HEIGHT));
dataUrl = null;
}
shooter.takeShot(captureType, selectedPos, dataUrl);
},
onDownloadPreview: () => {
@ -668,6 +673,9 @@ this.uicontrol = (function() {
mousemove(event) {
this._resize(event);
if (resizeDirection !== "move") {
ui.PixelDimensions.display(event.pageX, event.pageY, selectedPos.width, selectedPos.height);
}
return false;
},
@ -723,6 +731,7 @@ this.uicontrol = (function() {
end() {
resizeDirection = resizeStartPos = resizeStartSelected = null;
selectedPos.sortCoords();
ui.PixelDimensions.remove();
}
};

Просмотреть файл

@ -15,6 +15,12 @@ this.sitehelper = (function() {
});
const capabilities = {};
function registerListener(name, func) {
capabilities[name] = name;
document.addEventListener(name, func);
}
function sendCustomEvent(name, detail) {
if (typeof detail === "object") {
// Note sending an object can lead to security problems, while a string
@ -50,29 +56,39 @@ this.sitehelper = (function() {
};
}
document.addEventListener("delete-everything", catcher.watchFunction((event) => {
registerListener("delete-everything", catcher.watchFunction((event) => {
// FIXME: reset some data in the add-on
}, false));
document.addEventListener("request-login", catcher.watchFunction((event) => {
registerListener("request-login", catcher.watchFunction((event) => {
const shotId = event.detail;
catcher.watchPromise(callBackground("getAuthInfo", shotId || null).then((info) => {
if (info) {
sendBackupCookieRequest(info.authHeaders);
sendCustomEvent("login-successful", {deviceId: info.deviceId, isOwner: info.isOwner, backupCookieRequest: true});
sendCustomEvent("login-successful", {deviceId: info.deviceId, accountId: info.accountId, isOwner: info.isOwner, backupCookieRequest: true});
}
}));
}));
document.addEventListener("request-onboarding", catcher.watchFunction((event) => {
registerListener("request-onboarding", catcher.watchFunction((event) => {
callBackground("requestOnboarding");
}));
registerListener("copy-to-clipboard", catcher.watchFunction(event => {
catcher.watchPromise(callBackground("copyShotToClipboard", event.detail));
}));
registerListener("show-notification", catcher.watchFunction(event => {
catcher.watchPromise(callBackground("showNotification", event.detail));
}));
// Depending on the script loading order, the site might get the addon-present event,
// but probably won't - instead the site will ask for that event after it has loaded
document.addEventListener("request-addon-present", catcher.watchFunction(() => {
sendCustomEvent("addon-present");
registerListener("request-addon-present", catcher.watchFunction(() => {
sendCustomEvent("addon-present", capabilities);
}));
sendCustomEvent("addon-present");
sendCustomEvent("addon-present", capabilities);
})();
null;

Просмотреть файл

@ -1,6 +1,2 @@
[DEFAULT]
support-files =
head.js
[browser_screenshots_ui_check.js]
skip-if = os == 'win' && debug # Bug 1394967

Просмотреть файл

@ -1,5 +1,8 @@
"use strict";
ChromeUtils.defineModuleGetter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm");
const BUTTON_ID = "pageAction-panel-screenshots_mozilla_org";
function checkElements(expectPresent, l) {
@ -15,13 +18,12 @@ async function togglePageActionPanel() {
}
function promiseOpenPageActionPanel() {
const dwu = window.windowUtils;
return BrowserTestUtils.waitForCondition(() => {
// Wait for the main page action button to become visible. It's hidden for
// some URIs, so depending on when this is called, it may not yet be quite
// visible. It's up to the caller to make sure it will be visible.
info("Waiting for main page action button to have non-0 size");
const bounds = dwu.getBoundsWithoutFlushing(BrowserPageActions.mainButtonNode);
const bounds = window.windowUtils.getBoundsWithoutFlushing(BrowserPageActions.mainButtonNode);
return bounds.width > 0 && bounds.height > 0;
}).then(() => {
// Wait for the panel to become open, by clicking the button if necessary.
@ -54,11 +56,10 @@ function promisePageActionPanelEvent(eventType) {
function promisePageActionViewChildrenVisible(panelViewNode) {
info("promisePageActionViewChildrenVisible waiting for a child node to be visible");
const dwu = window.windowUtils;
return BrowserTestUtils.waitForCondition(() => {
const bodyNode = panelViewNode.firstElementChild;
for (const childNode of bodyNode.children) {
const bounds = dwu.getBoundsWithoutFlushing(childNode);
const bodyNode = panelViewNode.firstChild;
for (const childNode of bodyNode.childNodes) {
const bounds = window.windowUtils.getBoundsWithoutFlushing(childNode);
if (bounds.width > 0 && bounds.height > 0) {
return true;
}
@ -68,11 +69,15 @@ function promisePageActionViewChildrenVisible(panelViewNode) {
}
add_task(async function() {
await promiseScreenshotsEnabled();
registerCleanupFunction(async function() {
await promiseScreenshotsReset();
// If Screenshots was disabled, enable it just for this test.
const addon = await AddonManager.getAddonByID("screenshots@mozilla.org");
const isEnabled = addon.enabled;
if (!isEnabled) {
await addon.enable({allowSystemAddons: true});
registerCleanupFunction(async () => {
await addon.disable({allowSystemAddons: true});
});
}
// Toggle the page action panel to get it to rebuild itself. An actionable
// page must be opened first.

Просмотреть файл

@ -1,57 +0,0 @@
/* globals PageActions */
// Currently Screenshots is disabled in tests. We want these tests to work under
// either case that Screenshots is disabled or enabled on startup of the browser,
// and that at the end we're reset to the correct state.
let enabledOnStartup = false;
// ScreenshotsEnabled/Disabled promises return true if it was already
// Enabled/Disabled, and false if it need to Enable/Disable.
function promiseScreenshotsEnabled() {
if (!Services.prefs.getBoolPref("extensions.screenshots.disabled", false)) {
info("Screenshots was already enabled, assuming enabled by default for tests");
enabledOnStartup = true;
return Promise.resolve(true);
}
info("Screenshots is not enabled");
return new Promise((resolve, reject) => {
const interval = setInterval(() => {
const action = PageActions.actionForID("screenshots_mozilla_org");
if (action) {
info("screenshots page action created");
clearInterval(interval);
resolve(false);
}
}, 100);
info("Set Screenshots disabled pref to false.");
Services.prefs.setBoolPref("extensions.screenshots.disabled", false);
});
}
function promiseScreenshotsDisabled() {
if (Services.prefs.getBoolPref("extensions.screenshots.disabled", false)) {
info("Screenshots already disabled");
return Promise.resolve(true);
}
return new Promise((resolve, reject) => {
const interval = setInterval(() => {
const action = PageActions.actionForID("screenshots");
if (!action) {
info("screenshots page action removed");
clearInterval(interval);
resolve(false);
}
}, 100);
info("Set Screenshots disabled pref to true.");
Services.prefs.setBoolPref("extensions.screenshots.disabled", true);
});
}
function promiseScreenshotsReset() { // eslint-disable-line no-unused-vars
if (enabledOnStartup) {
info("Reset is enabling Screenshots addon");
return promiseScreenshotsEnabled();
}
info("Reset is disabling Screenshots addon");
return promiseScreenshotsDisabled();
}

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 30 KiB