fune/browser/components/translation/TranslationContentHandler.jsm
Kris Maglione e930b89c34 Bug 1514594: Part 3 - Change ChromeUtils.import API.
***
Bug 1514594: Part 3a - Change ChromeUtils.import to return an exports object; not pollute global. r=mccr8

This changes the behavior of ChromeUtils.import() to return an exports object,
rather than a module global, in all cases except when `null` is passed as a
second argument, and changes the default behavior not to pollute the global
scope with the module's exports. Thus, the following code written for the old
model:

  ChromeUtils.import("resource://gre/modules/Services.jsm");

is approximately the same as the following, in the new model:

  var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");

Since the two behaviors are mutually incompatible, this patch will land with a
scripted rewrite to update all existing callers to use the new model rather
than the old.
***
Bug 1514594: Part 3b - Mass rewrite all JS code to use the new ChromeUtils.import API. rs=Gijs

This was done using the followng script:

https://bitbucket.org/kmaglione/m-c-rewrites/src/tip/processors/cu-import-exports.jsm
***
Bug 1514594: Part 3c - Update ESLint plugin for ChromeUtils.import API changes. r=Standard8

Differential Revision: https://phabricator.services.mozilla.com/D16747
***
Bug 1514594: Part 3d - Remove/fix hundreds of duplicate imports from sync tests. r=Gijs

Differential Revision: https://phabricator.services.mozilla.com/D16748
***
Bug 1514594: Part 3e - Remove no-op ChromeUtils.import() calls. r=Gijs

Differential Revision: https://phabricator.services.mozilla.com/D16749
***
Bug 1514594: Part 3f.1 - Cleanup various test corner cases after mass rewrite. r=Gijs
***
Bug 1514594: Part 3f.2 - Cleanup various non-test corner cases after mass rewrite. r=Gijs

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

--HG--
extra : rebase_source : 359574ee3064c90f33bf36c2ebe3159a24cc8895
extra : histedit_source : b93c8f42808b1599f9122d7842d2c0b3e656a594%2C64a3a4e3359dc889e2ab2b49461bab9e27fc10a7
2019-01-17 10:18:31 -08:00

169 lines
5.7 KiB
JavaScript

/* 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/. */
"use strict";
var EXPORTED_SYMBOLS = [ "TranslationContentHandler" ];
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "LanguageDetector",
"resource:///modules/translation/LanguageDetector.jsm");
const STATE_OFFER = 0;
const STATE_TRANSLATED = 2;
const STATE_ERROR = 3;
var TranslationContentHandler = function(global, docShell) {
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
global.addEventListener("pageshow", this);
global.addMessageListener("Translation:TranslateDocument", this);
global.addMessageListener("Translation:ShowTranslation", this);
global.addMessageListener("Translation:ShowOriginal", this);
this.global = global;
};
TranslationContentHandler.prototype = {
handleEvent(aEvent) {
// We are only listening to pageshow events.
let target = aEvent.target;
// Only handle top-level frames.
let win = target.defaultView;
if (win.parent !== win)
return;
let content = this.global.content;
if (!content.detectedLanguage)
return;
let data = {};
let trDoc = content.translationDocument;
if (trDoc) {
data.state = trDoc.translationError ? STATE_ERROR : STATE_TRANSLATED;
data.translatedFrom = trDoc.translatedFrom;
data.translatedTo = trDoc.translatedTo;
data.originalShown = trDoc.originalShown;
} else {
data.state = STATE_OFFER;
data.originalShown = true;
}
data.detectedLanguage = content.detectedLanguage;
this.global.sendAsyncMessage("Translation:DocumentState", data);
},
/* nsIWebProgressListener implementation */
onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
if (!aWebProgress.isTopLevel ||
!(aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) ||
!this.global.content)
return;
try {
let url = aRequest.name;
if (!url.startsWith("http://") && !url.startsWith("https://"))
return;
} catch (e) {
// nsIRequest.name throws NS_ERROR_NOT_IMPLEMENTED for view-source: tabs.
return;
}
let content = this.global.content;
if (content.detectedLanguage)
return;
// Grab a 60k sample of text from the page.
let encoder = Cu.createDocumentEncoder("text/plain");
encoder.init(content.document, "text/plain", encoder.SkipInvisibleContent);
let string = encoder.encodeToStringWithMaxLength(60 * 1024);
// Language detection isn't reliable on very short strings.
if (string.length < 100)
return;
LanguageDetector.detectLanguage(string).then(result => {
// Bail if we're not confident.
if (!result.confident) {
return;
}
// The window might be gone by now.
if (Cu.isDeadWrapper(content)) {
return;
}
content.detectedLanguage = result.language;
let data = {
state: STATE_OFFER,
originalShown: true,
detectedLanguage: result.language,
};
this.global.sendAsyncMessage("Translation:DocumentState", data);
});
},
QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference]),
receiveMessage(msg) {
switch (msg.name) {
case "Translation:TranslateDocument":
{
var {TranslationDocument} = ChromeUtils.import("resource:///modules/translation/TranslationDocument.jsm");
// If a TranslationDocument already exists for this document, it should
// be used instead of creating a new one so that we can use the original
// content of the page for the new translation instead of the newly
// translated text.
let translationDocument = this.global.content.translationDocument ||
new TranslationDocument(this.global.content.document);
let engine = Services.prefs.getCharPref("browser.translation.engine");
let importScope =
ChromeUtils.import(`resource:///modules/translation/${engine}Translator.jsm`, {});
let translator = new importScope[engine + "Translator"](translationDocument,
msg.data.from,
msg.data.to);
this.global.content.translationDocument = translationDocument;
translationDocument.translatedFrom = msg.data.from;
translationDocument.translatedTo = msg.data.to;
translationDocument.translationError = false;
translator.translate().then(
result => {
this.global.sendAsyncMessage("Translation:Finished", {
characterCount: result.characterCount,
from: msg.data.from,
to: msg.data.to,
success: true,
});
translationDocument.showTranslation();
},
error => {
translationDocument.translationError = true;
let data = {success: false};
if (error == "unavailable")
data.unavailable = true;
this.global.sendAsyncMessage("Translation:Finished", data);
}
);
break;
}
case "Translation:ShowOriginal":
this.global.content.translationDocument.showOriginal();
break;
case "Translation:ShowTranslation":
this.global.content.translationDocument.showTranslation();
break;
}
},
};