зеркало из https://github.com/mozilla/gecko-dev.git
605 строки
20 KiB
JavaScript
605 строки
20 KiB
JavaScript
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
/* 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/. */
|
|
|
|
/* eslint-env mozilla/frame-script */
|
|
/* eslint no-unused-vars: ["error", {args: "none"}] */
|
|
/* global sendAsyncMessage */
|
|
|
|
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
ChromeUtils.defineModuleGetter(this, "AutoCompletePopup",
|
|
"resource://gre/modules/AutoCompletePopupContent.jsm");
|
|
ChromeUtils.defineModuleGetter(this, "AutoScrollController",
|
|
"resource://gre/modules/AutoScrollController.jsm");
|
|
ChromeUtils.defineModuleGetter(this, "BrowserUtils",
|
|
"resource://gre/modules/BrowserUtils.jsm");
|
|
ChromeUtils.defineModuleGetter(this, "SelectContentHelper",
|
|
"resource://gre/modules/SelectContentHelper.jsm");
|
|
ChromeUtils.defineModuleGetter(this, "FindContent",
|
|
"resource://gre/modules/FindContent.jsm");
|
|
ChromeUtils.defineModuleGetter(this, "PrintingContent",
|
|
"resource://gre/modules/PrintingContent.jsm");
|
|
ChromeUtils.defineModuleGetter(this, "RemoteFinder",
|
|
"resource://gre/modules/RemoteFinder.jsm");
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "formFill",
|
|
"@mozilla.org/satchel/form-fill-controller;1",
|
|
"nsIFormFillController");
|
|
|
|
var global = this;
|
|
|
|
XPCOMUtils.defineLazyProxy(this, "PopupBlocking", () => {
|
|
let tmp = {};
|
|
ChromeUtils.import("resource://gre/modules/PopupBlocking.jsm", tmp);
|
|
return new tmp.PopupBlocking(global);
|
|
});
|
|
|
|
XPCOMUtils.defineLazyProxy(this, "SelectionSourceContent",
|
|
"resource://gre/modules/SelectionSourceContent.jsm");
|
|
|
|
XPCOMUtils.defineLazyProxy(this, "DateTimePickerContent", () => {
|
|
let tmp = {};
|
|
ChromeUtils.import("resource://gre/modules/DateTimePickerContent.jsm", tmp);
|
|
return new tmp.DateTimePickerContent(this);
|
|
});
|
|
|
|
|
|
// Lazily load the finder code
|
|
addMessageListener("Finder:Initialize", function() {
|
|
let {RemoteFinderListener} = ChromeUtils.import("resource://gre/modules/RemoteFinder.jsm", {});
|
|
new RemoteFinderListener(global);
|
|
});
|
|
|
|
var AutoScrollListener = {
|
|
handleEvent(event) {
|
|
if (event.isTrusted &
|
|
!event.defaultPrevented &&
|
|
event.button == 1) {
|
|
if (!this._controller) {
|
|
this._controller = new AutoScrollController(global);
|
|
}
|
|
this._controller.handleEvent(event);
|
|
}
|
|
}
|
|
};
|
|
Services.els.addSystemEventListener(global, "mousedown", AutoScrollListener, true);
|
|
|
|
addEventListener("MozOpenDateTimePicker", DateTimePickerContent);
|
|
|
|
addEventListener("DOMPopupBlocked", PopupBlocking, true);
|
|
|
|
var Printing = {
|
|
MESSAGES: [
|
|
"Printing:Preview:Enter",
|
|
"Printing:Preview:Exit",
|
|
"Printing:Preview:Navigate",
|
|
"Printing:Preview:ParseDocument",
|
|
"Printing:Print",
|
|
],
|
|
|
|
init() {
|
|
this.MESSAGES.forEach(msgName => addMessageListener(msgName, this));
|
|
addEventListener("PrintingError", this, true);
|
|
addEventListener("printPreviewUpdate", this, true);
|
|
this.init = null;
|
|
},
|
|
|
|
handleEvent(event) {
|
|
return PrintingContent.handleEvent(global, event);
|
|
},
|
|
|
|
receiveMessage(message) {
|
|
return PrintingContent.receiveMessage(global, message);
|
|
},
|
|
};
|
|
Printing.init();
|
|
|
|
function SwitchDocumentDirection(aWindow) {
|
|
// document.dir can also be "auto", in which case it won't change
|
|
if (aWindow.document.dir == "ltr" || aWindow.document.dir == "") {
|
|
aWindow.document.dir = "rtl";
|
|
} else if (aWindow.document.dir == "rtl") {
|
|
aWindow.document.dir = "ltr";
|
|
}
|
|
for (let run = 0; run < aWindow.frames.length; run++) {
|
|
SwitchDocumentDirection(aWindow.frames[run]);
|
|
}
|
|
}
|
|
|
|
addMessageListener("SwitchDocumentDirection", () => {
|
|
SwitchDocumentDirection(content.window);
|
|
});
|
|
|
|
var FindBar = {
|
|
/* Please keep in sync with toolkit/content/widgets/findbar.xml */
|
|
FIND_NORMAL: 0,
|
|
FIND_TYPEAHEAD: 1,
|
|
FIND_LINKS: 2,
|
|
|
|
_findMode: 0,
|
|
|
|
/**
|
|
* _findKey and _findModifiers are used to determine whether a keypress
|
|
* is a user attempting to use the find shortcut, after which we'll
|
|
* route keypresses to the parent until we know the findbar has focus
|
|
* there. To do this, we need shortcut data from the parent.
|
|
*/
|
|
_findKey: null,
|
|
_findModifiers: null,
|
|
|
|
init() {
|
|
addMessageListener("Findbar:UpdateState", this);
|
|
Services.els.addSystemEventListener(global, "keypress", this, false);
|
|
Services.els.addSystemEventListener(global, "mouseup", this, false);
|
|
this._initShortcutData();
|
|
this.init = null;
|
|
},
|
|
|
|
receiveMessage(msg) {
|
|
switch (msg.name) {
|
|
case "Findbar:UpdateState":
|
|
this._findMode = msg.data.findMode;
|
|
this._quickFindTimeout = msg.data.hasQuickFindTimeout;
|
|
if (msg.data.isOpenAndFocused) {
|
|
this._keepPassingUntilToldOtherwise = false;
|
|
}
|
|
break;
|
|
case "Findbar:ShortcutData":
|
|
// Set us up to never need this again for the lifetime of this process,
|
|
// and remove the listener.
|
|
Services.cpmm.initialProcessData.findBarShortcutData = msg.data;
|
|
Services.cpmm.removeMessageListener("Findbar:ShortcutData", this);
|
|
this._initShortcutData(msg.data);
|
|
break;
|
|
}
|
|
},
|
|
|
|
handleEvent(event) {
|
|
switch (event.type) {
|
|
case "keypress":
|
|
this._onKeypress(event);
|
|
break;
|
|
case "mouseup":
|
|
this._onMouseup(event);
|
|
break;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Use initial process data for find key/modifier data if we have it.
|
|
* Otherwise, add a listener so we get the data when the parent process has
|
|
* it.
|
|
*/
|
|
_initShortcutData(data = Services.cpmm.initialProcessData.findBarShortcutData) {
|
|
if (data) {
|
|
this._findKey = data.key;
|
|
this._findModifiers = data.modifiers;
|
|
} else {
|
|
Services.cpmm.addMessageListener("Findbar:ShortcutData", this);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Check whether this key event will start the findbar in the parent,
|
|
* in which case we should pass any further key events to the parent to avoid
|
|
* them being lost.
|
|
* @param aEvent the key event to check.
|
|
*/
|
|
_eventMatchesFindShortcut(aEvent) {
|
|
let modifiers = this._findModifiers;
|
|
if (!modifiers) {
|
|
return false;
|
|
}
|
|
return aEvent.ctrlKey == modifiers.ctrlKey && aEvent.altKey == modifiers.altKey &&
|
|
aEvent.shiftKey == modifiers.shiftKey && aEvent.metaKey == modifiers.metaKey &&
|
|
aEvent.key == this._findKey;
|
|
},
|
|
|
|
/**
|
|
* Returns whether FAYT can be used for the given event in
|
|
* the current content state.
|
|
*/
|
|
_canAndShouldFastFind() {
|
|
let should = false;
|
|
let can = BrowserUtils.canFastFind(content);
|
|
if (can) {
|
|
// XXXgijs: why all these shenanigans? Why not use the event's target?
|
|
let focusedWindow = {};
|
|
let elt = Services.focus.getFocusedElementForWindow(content, true, focusedWindow);
|
|
let win = focusedWindow.value;
|
|
should = BrowserUtils.shouldFastFind(elt, win);
|
|
}
|
|
return { can, should };
|
|
},
|
|
|
|
_onKeypress(event) {
|
|
const FAYT_LINKS_KEY = "'";
|
|
const FAYT_TEXT_KEY = "/";
|
|
if (this._eventMatchesFindShortcut(event)) {
|
|
this._keepPassingUntilToldOtherwise = true;
|
|
}
|
|
// Useless keys:
|
|
if (event.ctrlKey || event.altKey || event.metaKey || event.defaultPrevented) {
|
|
return;
|
|
}
|
|
|
|
// Check the focused element etc.
|
|
let fastFind = this._canAndShouldFastFind();
|
|
|
|
// Can we even use find in this page at all?
|
|
if (!fastFind.can) {
|
|
return;
|
|
}
|
|
if (this._keepPassingUntilToldOtherwise) {
|
|
this._passKeyToParent(event);
|
|
return;
|
|
}
|
|
if (!fastFind.should) {
|
|
return;
|
|
}
|
|
|
|
let charCode = event.charCode;
|
|
// If the find bar is open and quick find is on, send the key to the parent.
|
|
if (this._findMode != this.FIND_NORMAL && this._quickFindTimeout) {
|
|
if (!charCode)
|
|
return;
|
|
this._passKeyToParent(event);
|
|
} else {
|
|
let key = charCode ? String.fromCharCode(charCode) : null;
|
|
let manualstartFAYT = (key == FAYT_LINKS_KEY || key == FAYT_TEXT_KEY) && RemoteFinder._manualFAYT;
|
|
let autostartFAYT = !manualstartFAYT && RemoteFinder._findAsYouType && key && key != " ";
|
|
if (manualstartFAYT || autostartFAYT) {
|
|
let mode = (key == FAYT_LINKS_KEY || (autostartFAYT && RemoteFinder._typeAheadLinksOnly)) ?
|
|
this.FIND_LINKS : this.FIND_TYPEAHEAD;
|
|
// Set _findMode immediately (without waiting for child->parent->child roundtrip)
|
|
// to ensure we pass any further keypresses, too.
|
|
this._findMode = mode;
|
|
this._passKeyToParent(event);
|
|
}
|
|
}
|
|
},
|
|
|
|
_passKeyToParent(event) {
|
|
event.preventDefault();
|
|
// These are the properties required to dispatch another 'real' event
|
|
// to the findbar in the parent in _dispatchKeypressEvent in findbar.xml .
|
|
// If you make changes here, verify that that method can still do its job.
|
|
const kRequiredProps = [
|
|
"type", "bubbles", "cancelable", "ctrlKey", "altKey", "shiftKey",
|
|
"metaKey", "keyCode", "charCode",
|
|
];
|
|
let fakeEvent = {};
|
|
for (let prop of kRequiredProps) {
|
|
fakeEvent[prop] = event[prop];
|
|
}
|
|
sendAsyncMessage("Findbar:Keypress", fakeEvent);
|
|
},
|
|
|
|
_onMouseup(event) {
|
|
if (this._findMode != this.FIND_NORMAL)
|
|
sendAsyncMessage("Findbar:Mouseup");
|
|
},
|
|
};
|
|
FindBar.init();
|
|
|
|
let WebChannelMessageToChromeListener = {
|
|
// Preference containing the list (space separated) of origins that are
|
|
// allowed to send non-string values through a WebChannel, mainly for
|
|
// backwards compatability. See bug 1238128 for more information.
|
|
URL_WHITELIST_PREF: "webchannel.allowObject.urlWhitelist",
|
|
|
|
// Cached list of whitelisted principals, we avoid constructing this if the
|
|
// value in `_lastWhitelistValue` hasn't changed since we constructed it last.
|
|
_cachedWhitelist: [],
|
|
_lastWhitelistValue: "",
|
|
|
|
init() {
|
|
addEventListener("WebChannelMessageToChrome", e => {
|
|
this._onMessageToChrome(e);
|
|
}, true, true);
|
|
},
|
|
|
|
_getWhitelistedPrincipals() {
|
|
let whitelist = Services.prefs.getCharPref(this.URL_WHITELIST_PREF);
|
|
if (whitelist != this._lastWhitelistValue) {
|
|
let urls = whitelist.split(/\s+/);
|
|
this._cachedWhitelist = urls.map(origin =>
|
|
Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(origin));
|
|
}
|
|
return this._cachedWhitelist;
|
|
},
|
|
|
|
_onMessageToChrome(e) {
|
|
// If target is window then we want the document principal, otherwise fallback to target itself.
|
|
let principal = e.target.nodePrincipal ? e.target.nodePrincipal : e.target.document.nodePrincipal;
|
|
|
|
if (e.detail) {
|
|
if (typeof e.detail != "string") {
|
|
// Check if the principal is one of the ones that's allowed to send
|
|
// non-string values for e.detail. They're whitelisted by site origin,
|
|
// so we compare on originNoSuffix in order to avoid other origin attributes
|
|
// that are not relevant here, such as containers or private browsing.
|
|
let objectsAllowed = this._getWhitelistedPrincipals().some(whitelisted =>
|
|
principal.originNoSuffix == whitelisted.originNoSuffix);
|
|
if (!objectsAllowed) {
|
|
Cu.reportError("WebChannelMessageToChrome sent with an object from a non-whitelisted principal");
|
|
return;
|
|
}
|
|
}
|
|
sendAsyncMessage("WebChannelMessageToChrome", e.detail, { eventTarget: e.target }, principal);
|
|
} else {
|
|
Cu.reportError("WebChannel message failed. No message detail.");
|
|
}
|
|
}
|
|
};
|
|
|
|
WebChannelMessageToChromeListener.init();
|
|
|
|
// This should be kept in sync with /browser/base/content.js.
|
|
// Add message listener for "WebChannelMessageToContent" messages from chrome scripts.
|
|
addMessageListener("WebChannelMessageToContent", function(e) {
|
|
if (e.data) {
|
|
// e.objects.eventTarget will be defined if sending a response to
|
|
// a WebChannelMessageToChrome event. An unsolicited send
|
|
// may not have an eventTarget defined, in this case send to the
|
|
// main content window.
|
|
let eventTarget = e.objects.eventTarget || content;
|
|
|
|
// Use nodePrincipal if available, otherwise fallback to document principal.
|
|
let targetPrincipal = eventTarget instanceof Ci.nsIDOMWindow ? eventTarget.document.nodePrincipal : eventTarget.nodePrincipal;
|
|
|
|
if (e.principal.subsumes(targetPrincipal)) {
|
|
// If eventTarget is a window, use it as the targetWindow, otherwise
|
|
// find the window that owns the eventTarget.
|
|
let targetWindow = eventTarget instanceof Ci.nsIDOMWindow ? eventTarget : eventTarget.ownerGlobal;
|
|
|
|
eventTarget.dispatchEvent(new targetWindow.CustomEvent("WebChannelMessageToContent", {
|
|
detail: Cu.cloneInto({
|
|
id: e.data.id,
|
|
message: e.data.message,
|
|
}, targetWindow),
|
|
}));
|
|
} else {
|
|
Cu.reportError("WebChannel message failed. Principal mismatch.");
|
|
}
|
|
} else {
|
|
Cu.reportError("WebChannel message failed. No message data.");
|
|
}
|
|
});
|
|
|
|
var AudioPlaybackListener = {
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
|
|
|
|
init() {
|
|
Services.obs.addObserver(this, "audio-playback");
|
|
|
|
addMessageListener("AudioPlayback", this);
|
|
addEventListener("unload", () => {
|
|
AudioPlaybackListener.uninit();
|
|
});
|
|
this.init = null;
|
|
},
|
|
|
|
uninit() {
|
|
Services.obs.removeObserver(this, "audio-playback");
|
|
|
|
removeMessageListener("AudioPlayback", this);
|
|
},
|
|
|
|
handleMediaControlMessage(msg) {
|
|
let utils = global.content.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
.getInterface(Ci.nsIDOMWindowUtils);
|
|
let suspendTypes = Ci.nsISuspendedTypes;
|
|
switch (msg) {
|
|
case "mute":
|
|
utils.audioMuted = true;
|
|
break;
|
|
case "unmute":
|
|
utils.audioMuted = false;
|
|
break;
|
|
case "lostAudioFocus":
|
|
utils.mediaSuspend = suspendTypes.SUSPENDED_PAUSE_DISPOSABLE;
|
|
break;
|
|
case "lostAudioFocusTransiently":
|
|
utils.mediaSuspend = suspendTypes.SUSPENDED_PAUSE;
|
|
break;
|
|
case "gainAudioFocus":
|
|
utils.mediaSuspend = suspendTypes.NONE_SUSPENDED;
|
|
break;
|
|
case "mediaControlPaused":
|
|
utils.mediaSuspend = suspendTypes.SUSPENDED_PAUSE_DISPOSABLE;
|
|
break;
|
|
case "mediaControlStopped":
|
|
utils.mediaSuspend = suspendTypes.SUSPENDED_STOP_DISPOSABLE;
|
|
break;
|
|
case "resumeMedia":
|
|
// User has clicked the tab audio indicator to play a delayed
|
|
// media. That's clear user intent to play, so gesture activate
|
|
// the content document tree so that the block-autoplay logic
|
|
// allows the media to autoplay.
|
|
content.document.notifyUserGestureActivation();
|
|
utils.mediaSuspend = suspendTypes.NONE_SUSPENDED;
|
|
break;
|
|
default:
|
|
dump("Error : wrong media control msg!\n");
|
|
break;
|
|
}
|
|
},
|
|
|
|
observe(subject, topic, data) {
|
|
if (topic === "audio-playback") {
|
|
if (subject && subject.top == global.content) {
|
|
let name = "AudioPlayback:";
|
|
if (data === "activeMediaBlockStart") {
|
|
name += "ActiveMediaBlockStart";
|
|
} else if (data === "activeMediaBlockStop") {
|
|
name += "ActiveMediaBlockStop";
|
|
} else {
|
|
name += (data === "active") ? "Start" : "Stop";
|
|
}
|
|
sendAsyncMessage(name);
|
|
}
|
|
}
|
|
},
|
|
|
|
receiveMessage(msg) {
|
|
if (msg.name == "AudioPlayback") {
|
|
this.handleMediaControlMessage(msg.data.type);
|
|
}
|
|
},
|
|
};
|
|
AudioPlaybackListener.init();
|
|
|
|
var UnselectedTabHoverObserver = {
|
|
init() {
|
|
addMessageListener("Browser:UnselectedTabHover", this);
|
|
addEventListener("UnselectedTabHover:Enable", this);
|
|
addEventListener("UnselectedTabHover:Disable", this);
|
|
this.init = null;
|
|
},
|
|
receiveMessage(message) {
|
|
Services.obs.notifyObservers(content.window, "unselected-tab-hover",
|
|
message.data.hovered);
|
|
},
|
|
handleEvent(event) {
|
|
sendAsyncMessage("UnselectedTabHover:Toggle",
|
|
{ enable: event.type == "UnselectedTabHover:Enable" });
|
|
}
|
|
};
|
|
UnselectedTabHoverObserver.init();
|
|
|
|
addMessageListener("Browser:PurgeSessionHistory", function BrowserPurgeHistory() {
|
|
let sessionHistory = docShell.QueryInterface(Ci.nsIWebNavigation).sessionHistory;
|
|
if (!sessionHistory) {
|
|
return;
|
|
}
|
|
|
|
// place the entry at current index at the end of the history list, so it won't get removed
|
|
if (sessionHistory.index < sessionHistory.count - 1) {
|
|
let legacy = sessionHistory.legacySHistory;
|
|
legacy.QueryInterface(Ci.nsISHistoryInternal);
|
|
let indexEntry = legacy.getEntryAtIndex(sessionHistory.index, false);
|
|
indexEntry.QueryInterface(Ci.nsISHEntry);
|
|
legacy.addEntry(indexEntry, true);
|
|
}
|
|
|
|
let purge = sessionHistory.count;
|
|
if (global.content.location.href != "about:blank") {
|
|
--purge; // Don't remove the page the user's staring at from shistory
|
|
}
|
|
|
|
if (purge > 0) {
|
|
sessionHistory.legacySHistory.PurgeHistory(purge);
|
|
}
|
|
});
|
|
|
|
addMessageListener("ViewSource:GetSelection", SelectionSourceContent);
|
|
|
|
addEventListener("MozApplicationManifest", function(e) {
|
|
let doc = e.target;
|
|
let info = {
|
|
uri: doc.documentURI,
|
|
characterSet: doc.characterSet,
|
|
manifest: doc.documentElement.getAttribute("manifest"),
|
|
principal: doc.nodePrincipal,
|
|
};
|
|
sendAsyncMessage("MozApplicationManifest", info);
|
|
}, false);
|
|
|
|
let AutoComplete = {
|
|
_connected: false,
|
|
|
|
init() {
|
|
addEventListener("unload", this, {once: true});
|
|
addEventListener("DOMContentLoaded", this, {once: true});
|
|
// WebExtension browserAction is preloaded and does not receive DCL, wait
|
|
// on pageshow so we can hookup the formfill controller.
|
|
addEventListener("pageshow", this, {capture: true, once: true});
|
|
|
|
XPCOMUtils.defineLazyProxy(this, "popup", () => new AutoCompletePopup(global),
|
|
{QueryInterface: null});
|
|
this.init = null;
|
|
},
|
|
|
|
handleEvent(event) {
|
|
switch (event.type) {
|
|
case "DOMContentLoaded":
|
|
case "pageshow":
|
|
// We need to wait for a content viewer to be available
|
|
// before we can attach our AutoCompletePopup handler,
|
|
// since nsFormFillController assumes one will exist
|
|
// when we call attachToBrowser.
|
|
if (!this._connected) {
|
|
formFill.attachToBrowser(docShell, this.popup);
|
|
this._connected = true;
|
|
}
|
|
break;
|
|
|
|
case "unload":
|
|
if (this._connected) {
|
|
formFill.detachFromBrowser(docShell);
|
|
this._connected = false;
|
|
}
|
|
break;
|
|
}
|
|
},
|
|
};
|
|
|
|
AutoComplete.init();
|
|
|
|
addEventListener("mozshowdropdown", event => {
|
|
if (!event.isTrusted)
|
|
return;
|
|
|
|
if (!SelectContentHelper.open) {
|
|
new SelectContentHelper(event.target, {isOpenedViaTouch: false}, this);
|
|
}
|
|
});
|
|
|
|
addEventListener("mozshowdropdown-sourcetouch", event => {
|
|
if (!event.isTrusted)
|
|
return;
|
|
|
|
if (!SelectContentHelper.open) {
|
|
new SelectContentHelper(event.target, {isOpenedViaTouch: true}, this);
|
|
}
|
|
});
|
|
|
|
let ExtFind = {
|
|
init() {
|
|
addMessageListener("ext-Finder:CollectResults", this);
|
|
addMessageListener("ext-Finder:HighlightResults", this);
|
|
addMessageListener("ext-Finder:clearHighlighting", this);
|
|
this.init = null;
|
|
},
|
|
|
|
_findContent: null,
|
|
|
|
async receiveMessage(message) {
|
|
if (!this._findContent) {
|
|
this._findContent = new FindContent(docShell);
|
|
}
|
|
|
|
let data;
|
|
switch (message.name) {
|
|
case "ext-Finder:CollectResults":
|
|
this.finderInited = true;
|
|
data = await this._findContent.findRanges(message.data);
|
|
sendAsyncMessage("ext-Finder:CollectResultsFinished", data);
|
|
break;
|
|
case "ext-Finder:HighlightResults":
|
|
data = this._findContent.highlightResults(message.data);
|
|
sendAsyncMessage("ext-Finder:HighlightResultsFinished", data);
|
|
break;
|
|
case "ext-Finder:clearHighlighting":
|
|
this._findContent.highlighter.highlight(false);
|
|
break;
|
|
}
|
|
},
|
|
};
|
|
|
|
ExtFind.init();
|