Merge f-t to m-c, a=merge
|
@ -347,6 +347,7 @@ pref("browser.urlbar.match.url", "@");
|
||||||
pref("browser.urlbar.suggest.history", true);
|
pref("browser.urlbar.suggest.history", true);
|
||||||
pref("browser.urlbar.suggest.bookmark", true);
|
pref("browser.urlbar.suggest.bookmark", true);
|
||||||
pref("browser.urlbar.suggest.openpage", true);
|
pref("browser.urlbar.suggest.openpage", true);
|
||||||
|
pref("browser.urlbar.suggest.searches", true);
|
||||||
|
|
||||||
// Restrictions to current suggestions can also be applied (intersection).
|
// Restrictions to current suggestions can also be applied (intersection).
|
||||||
// Typed suggestion works only if history is set to true.
|
// Typed suggestion works only if history is set to true.
|
||||||
|
@ -357,8 +358,8 @@ pref("browser.urlbar.trimURLs", true);
|
||||||
|
|
||||||
pref("browser.altClickSave", false);
|
pref("browser.altClickSave", false);
|
||||||
|
|
||||||
// Enable logging downloads operations to the Error Console.
|
// Enable logging downloads operations to the Console.
|
||||||
pref("browser.download.debug", false);
|
pref("browser.download.loglevel", "Error");
|
||||||
|
|
||||||
// Number of milliseconds to wait for the http headers (and thus
|
// Number of milliseconds to wait for the http headers (and thus
|
||||||
// the Content-Disposition filename) before giving up and falling back to
|
// the Content-Disposition filename) before giving up and falling back to
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
command="Browser:Stop"/>
|
command="Browser:Stop"/>
|
||||||
<menuitem id="context-bookmarkpage"
|
<menuitem id="context-bookmarkpage"
|
||||||
class="menuitem-iconic"
|
class="menuitem-iconic"
|
||||||
tooltiptext="&bookmarkPageCmd2.label;"
|
observes="bookmarkThisPageBroadcaster"
|
||||||
aria-label="&bookmarkPageCmd2.label;"
|
aria-label="&bookmarkPageCmd2.label;"
|
||||||
oncommand="gContextMenu.bookmarkThisPage();"/>
|
oncommand="gContextMenu.bookmarkThisPage();"/>
|
||||||
</menugroup>
|
</menugroup>
|
||||||
|
|
|
@ -1344,11 +1344,13 @@ let BookmarkingUI = {
|
||||||
|
|
||||||
if (aState == "invalid") {
|
if (aState == "invalid") {
|
||||||
this.star.setAttribute("disabled", "true");
|
this.star.setAttribute("disabled", "true");
|
||||||
this.button.removeAttribute("starred");
|
this.broadcaster.setAttribute("stardisabled", "true");
|
||||||
this.button.setAttribute("buttontooltiptext", "");
|
this.broadcaster.removeAttribute("starred");
|
||||||
|
this.broadcaster.setAttribute("buttontooltiptext", "");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.star.removeAttribute("disabled");
|
this.star.removeAttribute("disabled");
|
||||||
|
this.broadcaster.removeAttribute("stardisabled");
|
||||||
this._updateStar();
|
this._updateStar();
|
||||||
}
|
}
|
||||||
this._updateToolbarStyle();
|
this._updateToolbarStyle();
|
||||||
|
@ -1523,23 +1525,23 @@ let BookmarkingUI = {
|
||||||
|
|
||||||
_updateStar: function BUI__updateStar() {
|
_updateStar: function BUI__updateStar() {
|
||||||
if (!this._shouldUpdateStarState()) {
|
if (!this._shouldUpdateStarState()) {
|
||||||
if (this.button.hasAttribute("starred")) {
|
if (this.broadcaster.hasAttribute("starred")) {
|
||||||
this.button.removeAttribute("starred");
|
this.broadcaster.removeAttribute("starred");
|
||||||
this.button.removeAttribute("buttontooltiptext");
|
this.broadcaster.removeAttribute("buttontooltiptext");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._itemIds.length > 0) {
|
if (this._itemIds.length > 0) {
|
||||||
this.button.setAttribute("starred", "true");
|
this.broadcaster.setAttribute("starred", "true");
|
||||||
this.button.setAttribute("buttontooltiptext", this._starredTooltip);
|
this.broadcaster.setAttribute("buttontooltiptext", this._starredTooltip);
|
||||||
if (this.button.getAttribute("overflowedItem") == "true") {
|
if (this.button.getAttribute("overflowedItem") == "true") {
|
||||||
this.button.setAttribute("label", this._starButtonOverflowedStarredLabel);
|
this.button.setAttribute("label", this._starButtonOverflowedStarredLabel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.button.removeAttribute("starred");
|
this.broadcaster.removeAttribute("starred");
|
||||||
this.button.setAttribute("buttontooltiptext", this._unstarredTooltip);
|
this.broadcaster.setAttribute("buttontooltiptext", this._unstarredTooltip);
|
||||||
if (this.button.getAttribute("overflowedItem") == "true") {
|
if (this.button.getAttribute("overflowedItem") == "true") {
|
||||||
this.button.setAttribute("label", this._starButtonOverflowedLabel);
|
this.button.setAttribute("label", this._starButtonOverflowedLabel);
|
||||||
}
|
}
|
||||||
|
@ -1553,7 +1555,9 @@ let BookmarkingUI = {
|
||||||
_updateBookmarkPageMenuItem: function BUI__updateBookmarkPageMenuItem(forceReset) {
|
_updateBookmarkPageMenuItem: function BUI__updateBookmarkPageMenuItem(forceReset) {
|
||||||
let isStarred = !forceReset && this._itemIds.length > 0;
|
let isStarred = !forceReset && this._itemIds.length > 0;
|
||||||
let label = isStarred ? "editlabel" : "bookmarklabel";
|
let label = isStarred ? "editlabel" : "bookmarklabel";
|
||||||
this.broadcaster.setAttribute("label", this.broadcaster.getAttribute(label));
|
if (this.broadcaster) {
|
||||||
|
this.broadcaster.setAttribute("label", this.broadcaster.getAttribute(label));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onMainMenuPopupShowing: function BUI_onMainMenuPopupShowing(event) {
|
onMainMenuPopupShowing: function BUI_onMainMenuPopupShowing(event) {
|
||||||
|
@ -1671,6 +1675,10 @@ let BookmarkingUI = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onCurrentPageContextPopupShowing() {
|
||||||
|
this._updateBookmarkPageMenuItem();
|
||||||
|
},
|
||||||
|
|
||||||
handleEvent: function BUI_handleEvent(aEvent) {
|
handleEvent: function BUI_handleEvent(aEvent) {
|
||||||
switch (aEvent.type) {
|
switch (aEvent.type) {
|
||||||
case "ViewShowing":
|
case "ViewShowing":
|
||||||
|
|
|
@ -1328,3 +1328,28 @@ toolbarpaletteitem[place="palette"][hidden] {
|
||||||
#login-fill-doorhanger:not([inDetailView]) > #login-fill-clickcapturer {
|
#login-fill-doorhanger:not([inDetailView]) > #login-fill-clickcapturer {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.popup-notification-invalid-input {
|
||||||
|
box-shadow: 0 0 1.5px 1px red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-notification-invalid-input[focused] {
|
||||||
|
box-shadow: 0 0 2px 2px rgba(255,0,0,0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#password-notification-password::after {
|
||||||
|
color: hsl(0,0%,60%);
|
||||||
|
content: attr(show-content);
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
transition: color 250ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
#password-notification-password:hover::after {
|
||||||
|
color: hsl(210,100%,50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
#password-notification-password[focused]::after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
|
@ -7189,15 +7189,18 @@ let gPrivateBrowsingUI = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gURLBar &&
|
if (gURLBar) {
|
||||||
!PrivateBrowsingUtils.permanentPrivateBrowsing) {
|
|
||||||
// Disable switch to tab autocompletion for private windows.
|
|
||||||
// We leave it enabled for permanent private browsing mode though.
|
|
||||||
let value = gURLBar.getAttribute("autocompletesearchparam") || "";
|
let value = gURLBar.getAttribute("autocompletesearchparam") || "";
|
||||||
if (!value.includes("disable-private-actions")) {
|
if (!PrivateBrowsingUtils.permanentPrivateBrowsing &&
|
||||||
gURLBar.setAttribute("autocompletesearchparam",
|
!value.includes("disable-private-actions")) {
|
||||||
value + " disable-private-actions");
|
// Disable switch to tab autocompletion for private windows.
|
||||||
|
// We leave it enabled for permanent private browsing mode though.
|
||||||
|
value += " disable-private-actions";
|
||||||
}
|
}
|
||||||
|
if (!value.includes("private-window")) {
|
||||||
|
value += " private-window";
|
||||||
|
}
|
||||||
|
gURLBar.setAttribute("autocompletesearchparam", value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -821,6 +821,8 @@
|
||||||
ondrop="PlacesMenuDNDHandler.onDrop(event);"
|
ondrop="PlacesMenuDNDHandler.onDrop(event);"
|
||||||
cui-areatype="toolbar"
|
cui-areatype="toolbar"
|
||||||
oncommand="BookmarkingUI.onCommand(event);">
|
oncommand="BookmarkingUI.onCommand(event);">
|
||||||
|
<observes element="bookmarkThisPageBroadcaster" attribute="starred"/>
|
||||||
|
<observes element="bookmarkThisPageBroadcaster" attribute="buttontooltiptext"/>
|
||||||
<menupopup id="BMB_bookmarksPopup"
|
<menupopup id="BMB_bookmarksPopup"
|
||||||
class="cui-widget-panel cui-widget-panelview cui-widget-panelWithFooter PanelUI-subView"
|
class="cui-widget-panel cui-widget-panelview cui-widget-panelWithFooter PanelUI-subView"
|
||||||
placespopup="true"
|
placespopup="true"
|
||||||
|
|
|
@ -501,7 +501,8 @@ input[type=button] {
|
||||||
.newtab-search-panel-engine,
|
.newtab-search-panel-engine,
|
||||||
#newtab-search-manage {
|
#newtab-search-manage {
|
||||||
line-height: 25px;
|
line-height: 25px;
|
||||||
padding: 15px 15px 15px 40px;
|
padding: 15px;
|
||||||
|
-moz-padding-start: 40px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
@ -532,11 +533,20 @@ input[type=button] {
|
||||||
.newtab-customize-complex-option {
|
.newtab-customize-complex-option {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
text-align: left;
|
text-align: start;
|
||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
background-color: #F9F9F9;
|
background-color: #F9F9F9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.newtab-customize-panel-item[selected]:-moz-locale-dir(rtl) {
|
||||||
|
background-position: right 15px center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newtab-customize-complex-option:hover > .selectable:not([selected]):-moz-locale-dir(rtl),
|
||||||
|
.selectable:not([selected]):hover:-moz-locale-dir(rtl) {
|
||||||
|
background-position: right 15px center;
|
||||||
|
}
|
||||||
|
|
||||||
.newtab-intro-image-customize .newtab-customize-panel-item,
|
.newtab-intro-image-customize .newtab-customize-panel-item,
|
||||||
.newtab-intro-image-customize .newtab-customize-complex-option {
|
.newtab-intro-image-customize .newtab-customize-complex-option {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
@ -589,12 +599,13 @@ input[type=button] {
|
||||||
|
|
||||||
.newtab-customize-panel-subitem {
|
.newtab-customize-panel-subitem {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 0px 15px 15px 40px;
|
padding: 0px 15px 15px 15px;
|
||||||
|
-moz-padding-start: 40px;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.newtab-customize-panel-subitem > label {
|
.newtab-customize-panel-subitem > label {
|
||||||
padding-left: 10px;
|
padding: 0px 10px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
max-width: 225px;
|
max-width: 225px;
|
||||||
|
@ -603,7 +614,8 @@ input[type=button] {
|
||||||
.newtab-customize-panel-superitem {
|
.newtab-customize-panel-superitem {
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
border-bottom: medium none !important;
|
border-bottom: medium none !important;
|
||||||
padding: 15px 15px 10px 40px;
|
padding: 15px 15px 10px 15px;
|
||||||
|
-moz-padding-start: 40px;
|
||||||
border-top: 1px solid threedshadow;
|
border-top: 1px solid threedshadow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,10 @@ nsContextMenu.prototype = {
|
||||||
this.isContentSelected = !this.selectionInfo.docSelectionIsCollapsed;
|
this.isContentSelected = !this.selectionInfo.docSelectionIsCollapsed;
|
||||||
this.onPlainTextLink = false;
|
this.onPlainTextLink = false;
|
||||||
|
|
||||||
|
let bookmarkPage = document.getElementById("context-bookmarkpage");
|
||||||
|
if (bookmarkPage)
|
||||||
|
BookmarkingUI.onCurrentPageContextPopupShowing();
|
||||||
|
|
||||||
// Initialize (disable/remove) menu items.
|
// Initialize (disable/remove) menu items.
|
||||||
this.initItems();
|
this.initItems();
|
||||||
|
|
||||||
|
@ -269,10 +273,14 @@ nsContextMenu.prototype = {
|
||||||
|
|
||||||
initMiscItems: function CM_initMiscItems() {
|
initMiscItems: function CM_initMiscItems() {
|
||||||
// Use "Bookmark This Link" if on a link.
|
// Use "Bookmark This Link" if on a link.
|
||||||
this.showItem("context-bookmarkpage",
|
let bookmarkPage = document.getElementById("context-bookmarkpage");
|
||||||
|
this.showItem(bookmarkPage,
|
||||||
!(this.isContentSelected || this.onTextInput || this.onLink ||
|
!(this.isContentSelected || this.onTextInput || this.onLink ||
|
||||||
this.onImage || this.onVideo || this.onAudio || this.onSocial ||
|
this.onImage || this.onVideo || this.onAudio || this.onSocial ||
|
||||||
this.onCanvas));
|
this.onCanvas));
|
||||||
|
bookmarkPage.setAttribute("tooltiptext", bookmarkPage.getAttribute("buttontooltiptext"));
|
||||||
|
bookmarkPage.disabled = bookmarkPage.hasAttribute("stardisabled");
|
||||||
|
|
||||||
this.showItem("context-bookmarklink", (this.onLink && !this.onMailtoLink &&
|
this.showItem("context-bookmarklink", (this.onLink && !this.onMailtoLink &&
|
||||||
!this.onSocial) || this.onPlainTextLink);
|
!this.onSocial) || this.onPlainTextLink);
|
||||||
this.showItem("context-keywordfield",
|
this.showItem("context-keywordfield",
|
||||||
|
|
|
@ -57,8 +57,7 @@
|
||||||
<popupnotification id="password-notification" hidden="true">
|
<popupnotification id="password-notification" hidden="true">
|
||||||
<popupnotificationcontent orient="vertical">
|
<popupnotificationcontent orient="vertical">
|
||||||
<textbox id="password-notification-username"/>
|
<textbox id="password-notification-username"/>
|
||||||
<textbox id="password-notification-password" type="password"
|
<textbox id="password-notification-password" type="password" show-content=""/>
|
||||||
disabled="true"/>
|
|
||||||
</popupnotificationcontent>
|
</popupnotificationcontent>
|
||||||
</popupnotification>
|
</popupnotification>
|
||||||
|
|
||||||
|
|
|
@ -33,10 +33,7 @@ this.EXPORTED_SYMBOLS = [
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// Globals
|
//// Globals
|
||||||
|
|
||||||
const Cc = Components.classes;
|
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||||
const Ci = Components.interfaces;
|
|
||||||
const Cu = Components.utils;
|
|
||||||
const Cr = Components.results;
|
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
@ -65,8 +62,15 @@ XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||||
"resource://gre/modules/Promise.jsm");
|
"resource://gre/modules/Promise.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||||
"resource://gre/modules/Task.jsm");
|
"resource://gre/modules/Task.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsLogger",
|
|
||||||
"resource:///modules/DownloadsLogger.jsm");
|
XPCOMUtils.defineLazyGetter(this, "DownloadsLogger", () => {
|
||||||
|
let { ConsoleAPI } = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
|
||||||
|
let consoleOptions = {
|
||||||
|
maxLogLevelPref: "browser.download.loglevel",
|
||||||
|
prefix: "Downloads"
|
||||||
|
};
|
||||||
|
return new ConsoleAPI(consoleOptions);
|
||||||
|
});
|
||||||
|
|
||||||
const nsIDM = Ci.nsIDownloadManager;
|
const nsIDM = Ci.nsIDownloadManager;
|
||||||
|
|
||||||
|
@ -124,7 +128,6 @@ let PrefObserver = {
|
||||||
|
|
||||||
PrefObserver.register({
|
PrefObserver.register({
|
||||||
// prefName: defaultValue
|
// prefName: defaultValue
|
||||||
debug: false,
|
|
||||||
animateNotifications: true
|
animateNotifications: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -144,20 +147,6 @@ this.DownloadsCommon = {
|
||||||
BLOCK_VERDICT_POTENTIALLY_UNWANTED: "PotentiallyUnwanted",
|
BLOCK_VERDICT_POTENTIALLY_UNWANTED: "PotentiallyUnwanted",
|
||||||
BLOCK_VERDICT_UNCOMMON: "Uncommon",
|
BLOCK_VERDICT_UNCOMMON: "Uncommon",
|
||||||
|
|
||||||
log(...aMessageArgs) {
|
|
||||||
if (!PrefObserver.debug) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
DownloadsLogger.log(...aMessageArgs);
|
|
||||||
},
|
|
||||||
|
|
||||||
error(...aMessageArgs) {
|
|
||||||
if (!PrefObserver.debug) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
DownloadsLogger.reportError(...aMessageArgs);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an object whose keys are the string names from the downloads string
|
* Returns an object whose keys are the string names from the downloads string
|
||||||
* bundle, and whose values are either the translated strings or functions
|
* bundle, and whose values are either the translated strings or functions
|
||||||
|
@ -601,6 +590,13 @@ this.DownloadsCommon = {
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyGetter(this.DownloadsCommon, "log", () => {
|
||||||
|
return DownloadsLogger.log.bind(DownloadsLogger);
|
||||||
|
});
|
||||||
|
XPCOMUtils.defineLazyGetter(this.DownloadsCommon, "error", () => {
|
||||||
|
return DownloadsLogger.error.bind(DownloadsLogger);
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if we are executing on Windows Vista or a later version.
|
* Returns true if we are executing on Windows Vista or a later version.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
|
|
||||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The contents of this file were copied almost entirely from
|
|
||||||
* toolkit/identity/LogUtils.jsm. Until we've got a more generalized logging
|
|
||||||
* mechanism for toolkit, I think this is going to be how we roll.
|
|
||||||
*/
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
this.EXPORTED_SYMBOLS = ["DownloadsLogger"];
|
|
||||||
const PREF_DEBUG = "browser.download.debug";
|
|
||||||
|
|
||||||
const Cu = Components.utils;
|
|
||||||
const Ci = Components.interfaces;
|
|
||||||
const Cc = Components.classes;
|
|
||||||
const Cr = Components.results;
|
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
|
||||||
|
|
||||||
this.DownloadsLogger = {
|
|
||||||
_generateLogMessage(args) {
|
|
||||||
// create a string representation of a list of arbitrary things
|
|
||||||
let strings = [];
|
|
||||||
|
|
||||||
for (let arg of args) {
|
|
||||||
if (typeof arg === 'string') {
|
|
||||||
strings.push(arg);
|
|
||||||
} else if (arg === undefined) {
|
|
||||||
strings.push('undefined');
|
|
||||||
} else if (arg === null) {
|
|
||||||
strings.push('null');
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
strings.push(JSON.stringify(arg, null, 2));
|
|
||||||
} catch(err) {
|
|
||||||
strings.push("<<something>>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return 'Downloads: ' + strings.join(' ');
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* log() - utility function to print a list of arbitrary things
|
|
||||||
*
|
|
||||||
* Enable with about:config pref browser.download.debug
|
|
||||||
*/
|
|
||||||
log(...args) {
|
|
||||||
let output = this._generateLogMessage(args);
|
|
||||||
dump(output + "\n");
|
|
||||||
|
|
||||||
// Additionally, make the output visible in the Error Console
|
|
||||||
Services.console.logStringMessage(output);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* reportError() - report an error through component utils as well as
|
|
||||||
* our log function
|
|
||||||
*/
|
|
||||||
reportError(...aArgs) {
|
|
||||||
// Report the error in the browser
|
|
||||||
let output = this._generateLogMessage(aArgs);
|
|
||||||
Cu.reportError(output);
|
|
||||||
dump("ERROR:" + output + "\n");
|
|
||||||
for (let frame = Components.stack.caller; frame; frame = frame.caller) {
|
|
||||||
dump("\t" + frame + "\n");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -14,7 +14,6 @@ JAR_MANIFESTS += ['jar.mn']
|
||||||
|
|
||||||
EXTRA_JS_MODULES += [
|
EXTRA_JS_MODULES += [
|
||||||
'DownloadsCommon.jsm',
|
'DownloadsCommon.jsm',
|
||||||
'DownloadsLogger.jsm',
|
|
||||||
'DownloadsTaskbar.jsm',
|
'DownloadsTaskbar.jsm',
|
||||||
'DownloadsViewUI.jsm',
|
'DownloadsViewUI.jsm',
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,260 @@
|
||||||
|
/* 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";
|
||||||
|
|
||||||
|
const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||||
|
Cu.import("resource://gre/modules/Task.jsm");
|
||||||
|
Cu.import("resource:///modules/MigrationUtils.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||||
|
"resource://gre/modules/PlacesUtils.jsm");
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "Sqlite",
|
||||||
|
"resource://gre/modules/Sqlite.jsm");
|
||||||
|
|
||||||
|
function parseINIStrings(file) {
|
||||||
|
let factory = Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
|
||||||
|
getService(Ci.nsIINIParserFactory);
|
||||||
|
let parser = factory.createINIParser(file);
|
||||||
|
let obj = {};
|
||||||
|
let sections = parser.getSections();
|
||||||
|
while (sections.hasMore()) {
|
||||||
|
let section = sections.getNext();
|
||||||
|
obj[section] = {};
|
||||||
|
|
||||||
|
let keys = parser.getKeys(section);
|
||||||
|
while (keys.hasMore()) {
|
||||||
|
let key = keys.getNext();
|
||||||
|
obj[section][key] = parser.getString(section, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHash(aStr) {
|
||||||
|
// return the two-digit hexadecimal code for a byte
|
||||||
|
function toHexString(charCode)
|
||||||
|
("0" + charCode.toString(16)).slice(-2);
|
||||||
|
|
||||||
|
let hasher = Cc["@mozilla.org/security/hash;1"].
|
||||||
|
createInstance(Ci.nsICryptoHash);
|
||||||
|
hasher.init(Ci.nsICryptoHash.MD5);
|
||||||
|
let stringStream = Cc["@mozilla.org/io/string-input-stream;1"].
|
||||||
|
createInstance(Ci.nsIStringInputStream);
|
||||||
|
stringStream.data = aStr;
|
||||||
|
hasher.updateFromStream(stringStream, -1);
|
||||||
|
|
||||||
|
// convert the binary hash data to a hex string.
|
||||||
|
let binary = hasher.finish(false);
|
||||||
|
return [toHexString(binary.charCodeAt(i)) for (i in binary)].join("").toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function Bookmarks(aProfileFolder) {
|
||||||
|
let file = aProfileFolder.clone();
|
||||||
|
file.append("360sefav.db");
|
||||||
|
|
||||||
|
this._file = file;
|
||||||
|
}
|
||||||
|
Bookmarks.prototype = {
|
||||||
|
type: MigrationUtils.resourceTypes.BOOKMARKS,
|
||||||
|
|
||||||
|
get exists() {
|
||||||
|
return this._file.exists() && this._file.isReadable();
|
||||||
|
},
|
||||||
|
|
||||||
|
migrate: function (aCallback) {
|
||||||
|
return Task.spawn(function* () {
|
||||||
|
let idToGuid = new Map();
|
||||||
|
let folderGuid = PlacesUtils.bookmarks.toolbarGuid;
|
||||||
|
if (!MigrationUtils.isStartupMigration) {
|
||||||
|
folderGuid =
|
||||||
|
yield MigrationUtils.createImportedBookmarksFolder("360se", folderGuid);
|
||||||
|
}
|
||||||
|
idToGuid.set(0, folderGuid);
|
||||||
|
|
||||||
|
let connection = yield Sqlite.openConnection({
|
||||||
|
path: this._file.path
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
let rows = yield connection.execute(
|
||||||
|
`WITH RECURSIVE
|
||||||
|
bookmark(id, parent_id, is_folder, title, url, pos) AS (
|
||||||
|
VALUES(0, -1, 1, '', '', 0)
|
||||||
|
UNION
|
||||||
|
SELECT f.id, f.parent_id, f.is_folder, f.title, f.url, f.pos
|
||||||
|
FROM tb_fav AS f
|
||||||
|
JOIN bookmark AS b ON f.parent_id = b.id
|
||||||
|
ORDER BY f.pos ASC
|
||||||
|
)
|
||||||
|
SELECT id, parent_id, is_folder, title, url FROM bookmark WHERE id`);
|
||||||
|
|
||||||
|
for (let row of rows) {
|
||||||
|
let id = parseInt(row.getResultByName("id"), 10),
|
||||||
|
parent_id = parseInt(row.getResultByName("parent_id"), 10),
|
||||||
|
is_folder = parseInt(row.getResultByName("is_folder"), 10),
|
||||||
|
title = row.getResultByName("title"),
|
||||||
|
url = row.getResultByName("url");
|
||||||
|
|
||||||
|
let parentGuid = idToGuid.get(parent_id) || idToGuid.get("fallback");
|
||||||
|
if (!parentGuid) {
|
||||||
|
parentGuid = PlacesUtils.bookmarks.unfiledGuid;
|
||||||
|
if (!MigrationUtils.isStartupMigration) {
|
||||||
|
parentGuid =
|
||||||
|
yield MigrationUtils.createImportedBookmarksFolder("360se", parentGuid);
|
||||||
|
}
|
||||||
|
idToGuid.set("fallback", parentGuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (is_folder == 1) {
|
||||||
|
let newFolderGuid = (yield PlacesUtils.bookmarks.insert({
|
||||||
|
parentGuid,
|
||||||
|
type: PlacesUtils.bookmarks.TYPE_FOLDER,
|
||||||
|
title
|
||||||
|
})).guid;
|
||||||
|
|
||||||
|
idToGuid.set(id, newFolderGuid);
|
||||||
|
} else {
|
||||||
|
yield PlacesUtils.bookmarks.insert({
|
||||||
|
parentGuid,
|
||||||
|
url,
|
||||||
|
title
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
Cu.reportError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
yield connection.close();
|
||||||
|
}
|
||||||
|
}.bind(this)).then(() => aCallback(true),
|
||||||
|
e => { Cu.reportError(e); aCallback(false) });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function Qihoo360seProfileMigrator() {
|
||||||
|
let paths = [
|
||||||
|
// for v6 and above
|
||||||
|
{
|
||||||
|
users: ["360se6", "apps", "data", "users"],
|
||||||
|
defaultUser: "default"
|
||||||
|
},
|
||||||
|
// for earlier versions
|
||||||
|
{
|
||||||
|
users: ["360se"],
|
||||||
|
defaultUser: "data"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
this._usersDir = null;
|
||||||
|
this._defaultUserPath = null;
|
||||||
|
for (let path of paths) {
|
||||||
|
let usersDir = FileUtils.getDir("AppData", path.users, false);
|
||||||
|
if (usersDir.exists()) {
|
||||||
|
this._usersDir = usersDir;
|
||||||
|
this._defaultUserPath = path.defaultUser;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Qihoo360seProfileMigrator.prototype = Object.create(MigratorPrototype);
|
||||||
|
|
||||||
|
Object.defineProperty(Qihoo360seProfileMigrator.prototype, "sourceProfiles", {
|
||||||
|
get: function() {
|
||||||
|
if ("__sourceProfiles" in this)
|
||||||
|
return this.__sourceProfiles;
|
||||||
|
|
||||||
|
if (!this._usersDir)
|
||||||
|
return this.__sourceProfiles = [];
|
||||||
|
|
||||||
|
let profiles = [];
|
||||||
|
let noLoggedInUser = true;
|
||||||
|
try {
|
||||||
|
let loginIni = this._usersDir.clone();
|
||||||
|
loginIni.append("login.ini");
|
||||||
|
if (!loginIni.exists()) {
|
||||||
|
throw new Error("360 Secure Browser's 'login.ini' does not exist.");
|
||||||
|
}
|
||||||
|
if (!loginIni.isReadable()) {
|
||||||
|
throw new Error("360 Secure Browser's 'login.ini' file could not be read.");
|
||||||
|
}
|
||||||
|
let loginIniObj = parseINIStrings(loginIni);
|
||||||
|
let nowLoginEmail = loginIniObj.NowLogin && loginIniObj.NowLogin.email;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NowLogin section may:
|
||||||
|
* 1. be missing or without email, before any user logs in.
|
||||||
|
* 2. represents the current logged in user
|
||||||
|
* 3. represents the most recent logged in user
|
||||||
|
*
|
||||||
|
* In the second case, user represented by NowLogin should be the first
|
||||||
|
* profile; otherwise the default user should be selected by default.
|
||||||
|
*/
|
||||||
|
if (nowLoginEmail) {
|
||||||
|
if (loginIniObj.NowLogin.IsLogined === "1") {
|
||||||
|
noLoggedInUser = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
profiles.push({
|
||||||
|
id: this._getIdFromConfig(loginIniObj.NowLogin),
|
||||||
|
name: nowLoginEmail,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let section in loginIniObj) {
|
||||||
|
if (!loginIniObj[section].email ||
|
||||||
|
(nowLoginEmail && loginIniObj[section].email == nowLoginEmail)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
profiles.push({
|
||||||
|
id: this._getIdFromConfig(loginIniObj[section]),
|
||||||
|
name: loginIniObj[section].email,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Cu.reportError("Error detecting 360 Secure Browser profiles: " + e);
|
||||||
|
} finally {
|
||||||
|
profiles[noLoggedInUser ? "unshift" : "push"]({
|
||||||
|
id: this._defaultUserPath,
|
||||||
|
name: "Default",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.__sourceProfiles = profiles.filter(profile => {
|
||||||
|
let resources = this.getResources(profile);
|
||||||
|
return resources && resources.length > 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Qihoo360seProfileMigrator.prototype._getIdFromConfig = function(aConfig) {
|
||||||
|
return aConfig.UserMd5 || getHash(aConfig.email);
|
||||||
|
};
|
||||||
|
|
||||||
|
Qihoo360seProfileMigrator.prototype.getResources = function(aProfile) {
|
||||||
|
let profileFolder = this._usersDir.clone();
|
||||||
|
profileFolder.append(aProfile.id);
|
||||||
|
|
||||||
|
if (!profileFolder.exists()) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
let resources = [
|
||||||
|
new Bookmarks(profileFolder)
|
||||||
|
];
|
||||||
|
return [r for each (r in resources) if (r.exists)];
|
||||||
|
};
|
||||||
|
|
||||||
|
Qihoo360seProfileMigrator.prototype.classDescription = "360 Secure Browser Profile Migrator";
|
||||||
|
Qihoo360seProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=360se";
|
||||||
|
Qihoo360seProfileMigrator.prototype.classID = Components.ID("{d0037b95-296a-4a4e-94b2-c3d075d20ab1}");
|
||||||
|
|
||||||
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Qihoo360seProfileMigrator]);
|
|
@ -12,3 +12,7 @@ contract @mozilla.org/profile/migrator;1?app=browser&type=ie {3d2532e3-4932-4774
|
||||||
component {4b609ecf-60b2-4655-9df4-dc149e474da1} SafariProfileMigrator.js
|
component {4b609ecf-60b2-4655-9df4-dc149e474da1} SafariProfileMigrator.js
|
||||||
contract @mozilla.org/profile/migrator;1?app=browser&type=safari {4b609ecf-60b2-4655-9df4-dc149e474da1}
|
contract @mozilla.org/profile/migrator;1?app=browser&type=safari {4b609ecf-60b2-4655-9df4-dc149e474da1}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAS_360SE_MIGRATOR
|
||||||
|
component {d0037b95-296a-4a4e-94b2-c3d075d20ab1} 360seProfileMigrator.js
|
||||||
|
contract @mozilla.org/profile/migrator;1?app=browser&type=360se {d0037b95-296a-4a4e-94b2-c3d075d20ab1}
|
||||||
|
#endif
|
||||||
|
|
|
@ -43,11 +43,12 @@ function getMigrationBundle() {
|
||||||
*/
|
*/
|
||||||
function getMigratorKeyForDefaultBrowser() {
|
function getMigratorKeyForDefaultBrowser() {
|
||||||
const APP_DESC_TO_KEY = {
|
const APP_DESC_TO_KEY = {
|
||||||
"Internet Explorer": "ie",
|
"Internet Explorer": "ie",
|
||||||
"Safari": "safari",
|
"Safari": "safari",
|
||||||
"Firefox": "firefox",
|
"Firefox": "firefox",
|
||||||
"Google Chrome": "chrome", // Windows, Linux
|
"Google Chrome": "chrome", // Windows, Linux
|
||||||
"Chrome": "chrome", // OS X
|
"Chrome": "chrome", // OS X
|
||||||
|
"360\u5b89\u5168\u6d4f\u89c8\u5668": "360se",
|
||||||
};
|
};
|
||||||
|
|
||||||
let browserDesc = "";
|
let browserDesc = "";
|
||||||
|
@ -450,6 +451,7 @@ this.MigrationUtils = Object.freeze({
|
||||||
* Supported values: ie (windows),
|
* Supported values: ie (windows),
|
||||||
* safari (mac/windows),
|
* safari (mac/windows),
|
||||||
* chrome (mac/windows/linux),
|
* chrome (mac/windows/linux),
|
||||||
|
* 360se (windows),
|
||||||
* firefox.
|
* firefox.
|
||||||
*
|
*
|
||||||
* If null is returned, either no data can be imported
|
* If null is returned, either no data can be imported
|
||||||
|
@ -482,7 +484,7 @@ this.MigrationUtils = Object.freeze({
|
||||||
get migrators() {
|
get migrators() {
|
||||||
let migratorKeysOrdered = [
|
let migratorKeysOrdered = [
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
"firefox", "ie", "chrome", "safari"
|
"firefox", "ie", "chrome", "safari", "360se"
|
||||||
#elifdef XP_MACOSX
|
#elifdef XP_MACOSX
|
||||||
"firefox", "safari", "chrome"
|
"firefox", "safari", "chrome"
|
||||||
#elifdef XP_UNIX
|
#elifdef XP_UNIX
|
||||||
|
|
|
@ -292,6 +292,9 @@ var MigrationWizard = {
|
||||||
case "firefox":
|
case "firefox":
|
||||||
source = "sourceNameFirefox";
|
source = "sourceNameFirefox";
|
||||||
break;
|
break;
|
||||||
|
case "360se":
|
||||||
|
source = "sourceName360se";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// semi-wallpaper for crash when multiple profiles exist, since we haven't initialized mSourceProfile in places
|
// semi-wallpaper for crash when multiple profiles exist, since we haven't initialized mSourceProfile in places
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
<radio id="ie" label="&importFromIE.label;" accesskey="&importFromIE.accesskey;"/>
|
<radio id="ie" label="&importFromIE.label;" accesskey="&importFromIE.accesskey;"/>
|
||||||
<radio id="chrome" label="&importFromChrome.label;" accesskey="&importFromChrome.accesskey;"/>
|
<radio id="chrome" label="&importFromChrome.label;" accesskey="&importFromChrome.accesskey;"/>
|
||||||
<radio id="safari" label="&importFromSafari.label;" accesskey="&importFromSafari.accesskey;"/>
|
<radio id="safari" label="&importFromSafari.label;" accesskey="&importFromSafari.accesskey;"/>
|
||||||
|
<radio id="360se" label="&importFrom360se.label;" accesskey="&importFrom360se.accesskey;"/>
|
||||||
#elifdef XP_MACOSX
|
#elifdef XP_MACOSX
|
||||||
<radio id="safari" label="&importFromSafari.label;" accesskey="&importFromSafari.accesskey;"/>
|
<radio id="safari" label="&importFromSafari.label;" accesskey="&importFromSafari.accesskey;"/>
|
||||||
<radio id="chrome" label="&importFromChrome.label;" accesskey="&importFromChrome.accesskey;"/>
|
<radio id="chrome" label="&importFromChrome.label;" accesskey="&importFromChrome.accesskey;"/>
|
||||||
|
|
|
@ -26,8 +26,10 @@ EXTRA_COMPONENTS += [
|
||||||
|
|
||||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||||
EXTRA_COMPONENTS += [
|
EXTRA_COMPONENTS += [
|
||||||
|
'360seProfileMigrator.js',
|
||||||
'IEProfileMigrator.js',
|
'IEProfileMigrator.js',
|
||||||
]
|
]
|
||||||
|
DEFINES['HAS_360SE_MIGRATOR'] = True
|
||||||
DEFINES['HAS_IE_MIGRATOR'] = True
|
DEFINES['HAS_IE_MIGRATOR'] = True
|
||||||
|
|
||||||
EXTRA_PP_COMPONENTS += [
|
EXTRA_PP_COMPONENTS += [
|
||||||
|
|
|
@ -67,6 +67,7 @@
|
||||||
<menuitem value="ko" label="&font.langGroup.korean;"/>
|
<menuitem value="ko" label="&font.langGroup.korean;"/>
|
||||||
<menuitem value="x-western" label="&font.langGroup.latin;"/>
|
<menuitem value="x-western" label="&font.langGroup.latin;"/>
|
||||||
<menuitem value="x-mlym" label="&font.langGroup.malayalam;"/>
|
<menuitem value="x-mlym" label="&font.langGroup.malayalam;"/>
|
||||||
|
<menuitem value="x-math" label="&font.langGroup.math;"/>
|
||||||
<menuitem value="x-orya" label="&font.langGroup.oriya;"/>
|
<menuitem value="x-orya" label="&font.langGroup.oriya;"/>
|
||||||
<menuitem value="x-sinh" label="&font.langGroup.sinhala;"/>
|
<menuitem value="x-sinh" label="&font.langGroup.sinhala;"/>
|
||||||
<menuitem value="x-tamil" label="&font.langGroup.tamil;"/>
|
<menuitem value="x-tamil" label="&font.langGroup.tamil;"/>
|
||||||
|
|
|
@ -358,12 +358,12 @@ var gPrivacyPane = {
|
||||||
* Update browser.urlbar.autocomplete.enabled when a
|
* Update browser.urlbar.autocomplete.enabled when a
|
||||||
* browser.urlbar.suggest.* pref is changed from the ui.
|
* browser.urlbar.suggest.* pref is changed from the ui.
|
||||||
*/
|
*/
|
||||||
writeSuggestionPref: function () {
|
writeSuggestionPref() {
|
||||||
let getVal = (aPref) => {
|
let getVal = (aPref) => {
|
||||||
return document.getElementById("browser.urlbar.suggest." + aPref).value;
|
return document.getElementById("browser.urlbar.suggest." + aPref).value;
|
||||||
}
|
}
|
||||||
// autocomplete.enabled is true if any of the suggestions is true
|
// autocomplete.enabled is true if any of the suggestions is true
|
||||||
let enabled = ["history", "bookmark", "openpage"].map(getVal).some(v => v);
|
let enabled = ["history", "bookmark", "openpage", "searches"].map(getVal).some(v => v);
|
||||||
Services.prefs.setBoolPref("browser.urlbar.autocomplete.enabled", enabled);
|
Services.prefs.setBoolPref("browser.urlbar.autocomplete.enabled", enabled);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,9 @@
|
||||||
<preference id="browser.urlbar.suggest.openpage"
|
<preference id="browser.urlbar.suggest.openpage"
|
||||||
name="browser.urlbar.suggest.openpage"
|
name="browser.urlbar.suggest.openpage"
|
||||||
type="bool"/>
|
type="bool"/>
|
||||||
|
<preference id="browser.urlbar.suggest.searches"
|
||||||
|
name="browser.urlbar.suggest.searches"
|
||||||
|
type="bool"/>
|
||||||
|
|
||||||
<!-- History -->
|
<!-- History -->
|
||||||
<preference id="places.history.enabled"
|
<preference id="places.history.enabled"
|
||||||
|
@ -254,4 +257,8 @@
|
||||||
onsyncfrompreference="return gPrivacyPane.writeSuggestionPref();"
|
onsyncfrompreference="return gPrivacyPane.writeSuggestionPref();"
|
||||||
accesskey="&locbar.openpage.accesskey;"
|
accesskey="&locbar.openpage.accesskey;"
|
||||||
preference="browser.urlbar.suggest.openpage"/>
|
preference="browser.urlbar.suggest.openpage"/>
|
||||||
|
<checkbox id="searchesSuggestion" label="&locbar.searches.label;"
|
||||||
|
onsyncfrompreference="return gPrivacyPane.writeSuggestionPref();"
|
||||||
|
accesskey="&locbar.searches.accesskey;"
|
||||||
|
preference="browser.urlbar.suggest.searches"/>
|
||||||
</groupbox>
|
</groupbox>
|
||||||
|
|
|
@ -15,6 +15,7 @@ function test() {
|
||||||
run_test_subset([
|
run_test_subset([
|
||||||
test_locbar_suggestion_retention("history", true),
|
test_locbar_suggestion_retention("history", true),
|
||||||
test_locbar_suggestion_retention("bookmark", true),
|
test_locbar_suggestion_retention("bookmark", true),
|
||||||
|
test_locbar_suggestion_retention("searches", true),
|
||||||
test_locbar_suggestion_retention("openpage", false),
|
test_locbar_suggestion_retention("openpage", false),
|
||||||
test_locbar_suggestion_retention("history", true),
|
test_locbar_suggestion_retention("history", true),
|
||||||
test_locbar_suggestion_retention("history", false),
|
test_locbar_suggestion_retention("history", false),
|
||||||
|
@ -22,4 +23,4 @@ function test() {
|
||||||
// reset all preferences to their default values once we're done
|
// reset all preferences to their default values once we're done
|
||||||
reset_preferences
|
reset_preferences
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -325,12 +325,12 @@ var gPrivacyPane = {
|
||||||
* Update browser.urlbar.autocomplete.enabled when a
|
* Update browser.urlbar.autocomplete.enabled when a
|
||||||
* browser.urlbar.suggest.* pref is changed from the ui.
|
* browser.urlbar.suggest.* pref is changed from the ui.
|
||||||
*/
|
*/
|
||||||
writeSuggestionPref: function PPP_writeSuggestionPref() {
|
writeSuggestionPref() {
|
||||||
let getVal = (aPref) => {
|
let getVal = (aPref) => {
|
||||||
return document.getElementById("browser.urlbar.suggest." + aPref).value;
|
return document.getElementById("browser.urlbar.suggest." + aPref).value;
|
||||||
}
|
}
|
||||||
// autocomplete.enabled is true if any of the suggestions is true
|
// autocomplete.enabled is true if any of the suggestions is true
|
||||||
let enabled = ["history", "bookmark", "openpage"].map(getVal).some(v => v);
|
let enabled = ["history", "bookmark", "openpage", "searches"].map(getVal).some(v => v);
|
||||||
Services.prefs.setBoolPref("browser.urlbar.autocomplete.enabled", enabled);
|
Services.prefs.setBoolPref("browser.urlbar.autocomplete.enabled", enabled);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,9 @@
|
||||||
<preference id="browser.urlbar.suggest.openpage"
|
<preference id="browser.urlbar.suggest.openpage"
|
||||||
name="browser.urlbar.suggest.openpage"
|
name="browser.urlbar.suggest.openpage"
|
||||||
type="bool"/>
|
type="bool"/>
|
||||||
|
<preference id="browser.urlbar.suggest.searches"
|
||||||
|
name="browser.urlbar.suggest.searches"
|
||||||
|
type="bool"/>
|
||||||
|
|
||||||
<!-- History -->
|
<!-- History -->
|
||||||
<preference id="places.history.enabled"
|
<preference id="places.history.enabled"
|
||||||
|
@ -280,6 +283,10 @@
|
||||||
onsyncfrompreference="return gPrivacyPane.writeSuggestionPref();"
|
onsyncfrompreference="return gPrivacyPane.writeSuggestionPref();"
|
||||||
accesskey="&locbar.openpage.accesskey;"
|
accesskey="&locbar.openpage.accesskey;"
|
||||||
preference="browser.urlbar.suggest.openpage"/>
|
preference="browser.urlbar.suggest.openpage"/>
|
||||||
|
<checkbox id="searchesSuggestion" label="&locbar.searches.label;"
|
||||||
|
onsyncfrompreference="return gPrivacyPane.writeSuggestionPref();"
|
||||||
|
accesskey="&locbar.searches.accesskey;"
|
||||||
|
preference="browser.urlbar.suggest.searches"/>
|
||||||
</vbox>
|
</vbox>
|
||||||
</groupbox>
|
</groupbox>
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ function test() {
|
||||||
run_test_subset([
|
run_test_subset([
|
||||||
test_locbar_suggestion_retention("history", true),
|
test_locbar_suggestion_retention("history", true),
|
||||||
test_locbar_suggestion_retention("bookmark", true),
|
test_locbar_suggestion_retention("bookmark", true),
|
||||||
|
test_locbar_suggestion_retention("searches", true),
|
||||||
test_locbar_suggestion_retention("openpage", false),
|
test_locbar_suggestion_retention("openpage", false),
|
||||||
test_locbar_suggestion_retention("history", true),
|
test_locbar_suggestion_retention("history", true),
|
||||||
test_locbar_suggestion_retention("history", false),
|
test_locbar_suggestion_retention("history", false),
|
||||||
|
@ -22,4 +23,4 @@ function test() {
|
||||||
// reset all preferences to their default values once we're done
|
// reset all preferences to their default values once we're done
|
||||||
reset_preferences
|
reset_preferences
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -839,17 +839,12 @@ let SessionStoreInternal = {
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If it's the first window load since app start...
|
* Registers and tracks a given window.
|
||||||
* - determine if we're reloading after a crash or a forced-restart
|
*
|
||||||
* - restore window state
|
|
||||||
* - restart downloads
|
|
||||||
* Set up event listeners for this window's tabs
|
|
||||||
* @param aWindow
|
* @param aWindow
|
||||||
* Window reference
|
* Window reference
|
||||||
* @param aInitialState
|
|
||||||
* The initial state to be loaded after startup (optional)
|
|
||||||
*/
|
*/
|
||||||
onLoad: function ssi_onLoad(aWindow, aInitialState = null) {
|
onLoad(aWindow) {
|
||||||
// return if window has already been initialized
|
// return if window has already been initialized
|
||||||
if (aWindow && aWindow.__SSi && this._windows[aWindow.__SSi])
|
if (aWindow && aWindow.__SSi && this._windows[aWindow.__SSi])
|
||||||
return;
|
return;
|
||||||
|
@ -874,14 +869,43 @@ let SessionStoreInternal = {
|
||||||
// and create its data object
|
// and create its data object
|
||||||
this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [], busy: false };
|
this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [], busy: false };
|
||||||
|
|
||||||
let isPrivateWindow = false;
|
|
||||||
if (PrivateBrowsingUtils.isWindowPrivate(aWindow))
|
if (PrivateBrowsingUtils.isWindowPrivate(aWindow))
|
||||||
this._windows[aWindow.__SSi].isPrivate = isPrivateWindow = true;
|
this._windows[aWindow.__SSi].isPrivate = true;
|
||||||
if (!this._isWindowLoaded(aWindow))
|
if (!this._isWindowLoaded(aWindow))
|
||||||
this._windows[aWindow.__SSi]._restoring = true;
|
this._windows[aWindow.__SSi]._restoring = true;
|
||||||
if (!aWindow.toolbar.visible)
|
if (!aWindow.toolbar.visible)
|
||||||
this._windows[aWindow.__SSi].isPopup = true;
|
this._windows[aWindow.__SSi].isPopup = true;
|
||||||
|
|
||||||
|
let tabbrowser = aWindow.gBrowser;
|
||||||
|
|
||||||
|
// add tab change listeners to all already existing tabs
|
||||||
|
for (let i = 0; i < tabbrowser.tabs.length; i++) {
|
||||||
|
this.onTabAdd(aWindow, tabbrowser.tabs[i], true);
|
||||||
|
}
|
||||||
|
// notification of tab add/remove/selection/show/hide
|
||||||
|
TAB_EVENTS.forEach(function(aEvent) {
|
||||||
|
tabbrowser.tabContainer.addEventListener(aEvent, this, true);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// Keep track of a browser's latest frameLoader.
|
||||||
|
aWindow.gBrowser.addEventListener("XULFrameLoaderCreated", this);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a given window.
|
||||||
|
*
|
||||||
|
* Windows are registered as soon as they are created but we need to wait for
|
||||||
|
* the session file to load, and the initial window's delayed startup to
|
||||||
|
* finish before initializing a window, i.e. restoring data into it.
|
||||||
|
*
|
||||||
|
* @param aWindow
|
||||||
|
* Window reference
|
||||||
|
* @param aInitialState
|
||||||
|
* The initial state to be loaded after startup (optional)
|
||||||
|
*/
|
||||||
|
initializeWindow(aWindow, aInitialState = null) {
|
||||||
|
let isPrivateWindow = PrivateBrowsingUtils.isWindowPrivate(aWindow);
|
||||||
|
|
||||||
// perform additional initialization when the first window is loading
|
// perform additional initialization when the first window is loading
|
||||||
if (RunState.isStopped) {
|
if (RunState.isStopped) {
|
||||||
RunState.setRunning();
|
RunState.setRunning();
|
||||||
|
@ -1007,20 +1031,6 @@ let SessionStoreInternal = {
|
||||||
// undoCloseWindow was executed.
|
// undoCloseWindow was executed.
|
||||||
this._restoreLastWindow = false;
|
this._restoreLastWindow = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var tabbrowser = aWindow.gBrowser;
|
|
||||||
|
|
||||||
// add tab change listeners to all already existing tabs
|
|
||||||
for (let i = 0; i < tabbrowser.tabs.length; i++) {
|
|
||||||
this.onTabAdd(aWindow, tabbrowser.tabs[i], true);
|
|
||||||
}
|
|
||||||
// notification of tab add/remove/selection/show/hide
|
|
||||||
TAB_EVENTS.forEach(function(aEvent) {
|
|
||||||
tabbrowser.tabContainer.addEventListener(aEvent, this, true);
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
// Keep track of a browser's latest frameLoader.
|
|
||||||
aWindow.gBrowser.addEventListener("XULFrameLoaderCreated", this);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1029,9 +1039,12 @@ let SessionStoreInternal = {
|
||||||
* Window reference
|
* Window reference
|
||||||
*/
|
*/
|
||||||
onBeforeBrowserWindowShown: function (aWindow) {
|
onBeforeBrowserWindowShown: function (aWindow) {
|
||||||
// Just call onLoad() directly if we're initialized already.
|
// Register the window.
|
||||||
|
this.onLoad(aWindow);
|
||||||
|
|
||||||
|
// Just call initializeWindow() directly if we're initialized already.
|
||||||
if (this._sessionInitialized) {
|
if (this._sessionInitialized) {
|
||||||
this.onLoad(aWindow);
|
this.initializeWindow(aWindow);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1067,13 +1080,13 @@ let SessionStoreInternal = {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._sessionInitialized) {
|
if (this._sessionInitialized) {
|
||||||
this.onLoad(aWindow);
|
this.initializeWindow(aWindow);
|
||||||
} else {
|
} else {
|
||||||
let initialState = this.initSession();
|
let initialState = this.initSession();
|
||||||
this._sessionInitialized = true;
|
this._sessionInitialized = true;
|
||||||
|
|
||||||
TelemetryStopwatch.start("FX_SESSION_RESTORE_STARTUP_ONLOAD_INITIAL_WINDOW_MS");
|
TelemetryStopwatch.start("FX_SESSION_RESTORE_STARTUP_ONLOAD_INITIAL_WINDOW_MS");
|
||||||
this.onLoad(aWindow, initialState);
|
this.initializeWindow(aWindow, initialState);
|
||||||
TelemetryStopwatch.finish("FX_SESSION_RESTORE_STARTUP_ONLOAD_INITIAL_WINDOW_MS");
|
TelemetryStopwatch.finish("FX_SESSION_RESTORE_STARTUP_ONLOAD_INITIAL_WINDOW_MS");
|
||||||
|
|
||||||
// Let everyone know we're done.
|
// Let everyone know we're done.
|
||||||
|
@ -2173,6 +2186,7 @@ let SessionStoreInternal = {
|
||||||
*/
|
*/
|
||||||
navigateAndRestore(tab, loadArguments, historyIndex) {
|
navigateAndRestore(tab, loadArguments, historyIndex) {
|
||||||
let window = tab.ownerDocument.defaultView;
|
let window = tab.ownerDocument.defaultView;
|
||||||
|
NS_ASSERT(window.__SSi, "tab's window must be tracked");
|
||||||
let browser = tab.linkedBrowser;
|
let browser = tab.linkedBrowser;
|
||||||
|
|
||||||
// Set tab title to "Connecting..." and start the throbber to pretend we're
|
// Set tab title to "Connecting..." and start the throbber to pretend we're
|
||||||
|
|
|
@ -30,6 +30,16 @@ add_task(function*() {
|
||||||
ok(parseInt(toolbox._host.frame.style.marginBottom, 10) == 0,
|
ok(parseInt(toolbox._host.frame.style.marginBottom, 10) == 0,
|
||||||
"The toolbox host is shown again");
|
"The toolbox host is shown again");
|
||||||
|
|
||||||
|
info("Try to minimize again using the keyboard shortcut");
|
||||||
|
yield minimizeWithShortcut(toolbox);
|
||||||
|
ok(parseInt(toolbox._host.frame.style.marginBottom, 10) < 0,
|
||||||
|
"The toolbox host has been hidden away with a negative-margin");
|
||||||
|
|
||||||
|
info("Try to maximize again using the keyboard shortcut");
|
||||||
|
yield maximizeWithShortcut(toolbox);
|
||||||
|
ok(parseInt(toolbox._host.frame.style.marginBottom, 10) == 0,
|
||||||
|
"The toolbox host is shown again");
|
||||||
|
|
||||||
info("Minimize again and switch to another tool");
|
info("Minimize again and switch to another tool");
|
||||||
yield minimize(toolbox);
|
yield minimize(toolbox);
|
||||||
let onMaximized = toolbox._host.once("maximized");
|
let onMaximized = toolbox._host.once("maximized");
|
||||||
|
@ -67,9 +77,27 @@ function* minimize(toolbox) {
|
||||||
yield onMinimized;
|
yield onMinimized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function* minimizeWithShortcut(toolbox) {
|
||||||
|
let key = toolbox.doc.getElementById("toolbox-minimize-key")
|
||||||
|
.getAttribute("key");
|
||||||
|
let onMinimized = toolbox._host.once("minimized");
|
||||||
|
EventUtils.synthesizeKey(key, {accelKey: true, shiftKey: true},
|
||||||
|
toolbox.doc.defaultView);
|
||||||
|
yield onMinimized;
|
||||||
|
}
|
||||||
|
|
||||||
function* maximize(toolbox) {
|
function* maximize(toolbox) {
|
||||||
let button = toolbox.doc.querySelector("#toolbox-dock-bottom-minimize");
|
let button = toolbox.doc.querySelector("#toolbox-dock-bottom-minimize");
|
||||||
let onMaximized = toolbox._host.once("maximized");
|
let onMaximized = toolbox._host.once("maximized");
|
||||||
EventUtils.synthesizeMouseAtCenter(button, {}, toolbox.doc.defaultView);
|
EventUtils.synthesizeMouseAtCenter(button, {}, toolbox.doc.defaultView);
|
||||||
yield onMaximized;
|
yield onMaximized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function* maximizeWithShortcut(toolbox) {
|
||||||
|
let key = toolbox.doc.getElementById("toolbox-minimize-key")
|
||||||
|
.getAttribute("key");
|
||||||
|
let onMaximized = toolbox._host.once("maximized");
|
||||||
|
EventUtils.synthesizeKey(key, {accelKey: true, shiftKey: true},
|
||||||
|
toolbox.doc.defaultView);
|
||||||
|
yield onMaximized;
|
||||||
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
/* globals gDevTools, DOMHelpers, toolboxStrings, InspectorFront, Selection,
|
/* globals gDevTools, DOMHelpers, toolboxStrings, InspectorFront, Selection,
|
||||||
getPerformanceActorsConnection, CommandUtils, DevToolsUtils, screenManager,
|
CommandUtils, DevToolsUtils, screenManager, oscpu, Hosts, is64Bit,
|
||||||
oscpu, Hosts, is64Bit */
|
osString, showDoorhanger, getHighlighterUtils, getPerformanceFront */
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
@ -21,24 +21,20 @@ let {Cc, Ci, Cu} = require("chrome");
|
||||||
let {Promise: promise} = require("resource://gre/modules/Promise.jsm");
|
let {Promise: promise} = require("resource://gre/modules/Promise.jsm");
|
||||||
let EventEmitter = require("devtools/toolkit/event-emitter");
|
let EventEmitter = require("devtools/toolkit/event-emitter");
|
||||||
let Telemetry = require("devtools/shared/telemetry");
|
let Telemetry = require("devtools/shared/telemetry");
|
||||||
let {getHighlighterUtils} = require("devtools/framework/toolbox-highlighter-utils");
|
|
||||||
let HUDService = require("devtools/webconsole/hudservice");
|
let HUDService = require("devtools/webconsole/hudservice");
|
||||||
let {showDoorhanger} = require("devtools/shared/doorhanger");
|
|
||||||
let sourceUtils = require("devtools/shared/source-utils");
|
let sourceUtils = require("devtools/shared/source-utils");
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
Cu.import("resource:///modules/devtools/gDevTools.jsm");
|
Cu.import("resource:///modules/devtools/gDevTools.jsm");
|
||||||
Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
|
Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
|
||||||
Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
|
Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
|
||||||
Cu.import("resource://gre/modules/Task.jsm");
|
Cu.import("resource://gre/modules/Task.jsm");
|
||||||
|
|
||||||
loader.lazyGetter(this, "Hosts", () => require("devtools/framework/toolbox-hosts").Hosts);
|
loader.lazyImporter(this, "CommandUtils",
|
||||||
|
"resource:///modules/devtools/DeveloperToolbar.jsm");
|
||||||
loader.lazyImporter(this, "CommandUtils", "resource:///modules/devtools/DeveloperToolbar.jsm");
|
|
||||||
|
|
||||||
loader.lazyGetter(this, "toolboxStrings", () => {
|
loader.lazyGetter(this, "toolboxStrings", () => {
|
||||||
let bundle = Services.strings.createBundle("chrome://browser/locale/devtools/toolbox.properties");
|
const properties = "chrome://browser/locale/devtools/toolbox.properties";
|
||||||
|
const bundle = Services.strings.createBundle(properties);
|
||||||
return (name, ...args) => {
|
return (name, ...args) => {
|
||||||
try {
|
try {
|
||||||
if (!args.length) {
|
if (!args.length) {
|
||||||
|
@ -51,22 +47,31 @@ loader.lazyGetter(this, "toolboxStrings", () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
loader.lazyRequireGetter(this, "getHighlighterUtils",
|
||||||
loader.lazyGetter(this, "Selection", () => require("devtools/framework/selection").Selection);
|
"devtools/framework/toolbox-highlighter-utils", true);
|
||||||
loader.lazyGetter(this, "InspectorFront", () => require("devtools/server/actors/inspector").InspectorFront);
|
loader.lazyRequireGetter(this, "Hosts",
|
||||||
loader.lazyRequireGetter(this, "DevToolsUtils", "devtools/toolkit/DevToolsUtils");
|
"devtools/framework/toolbox-hosts", true);
|
||||||
loader.lazyRequireGetter(this, "getPerformanceFront", "devtools/performance/front", true);
|
loader.lazyRequireGetter(this, "Selection",
|
||||||
|
"devtools/framework/selection", true);
|
||||||
XPCOMUtils.defineLazyGetter(this, "screenManager", () => {
|
loader.lazyRequireGetter(this, "InspectorFront",
|
||||||
|
"devtools/server/actors/inspector", true);
|
||||||
|
loader.lazyRequireGetter(this, "DevToolsUtils",
|
||||||
|
"devtools/toolkit/DevToolsUtils");
|
||||||
|
loader.lazyRequireGetter(this, "showDoorhanger",
|
||||||
|
"devtools/shared/doorhanger", true);
|
||||||
|
loader.lazyRequireGetter(this, "getPerformanceFront",
|
||||||
|
"devtools/performance/front", true);
|
||||||
|
loader.lazyGetter(this, "osString", () => {
|
||||||
|
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
|
||||||
|
});
|
||||||
|
loader.lazyGetter(this, "screenManager", () => {
|
||||||
return Cc["@mozilla.org/gfx/screenmanager;1"].getService(Ci.nsIScreenManager);
|
return Cc["@mozilla.org/gfx/screenmanager;1"].getService(Ci.nsIScreenManager);
|
||||||
});
|
});
|
||||||
|
loader.lazyGetter(this, "oscpu", () => {
|
||||||
XPCOMUtils.defineLazyGetter(this, "oscpu", () => {
|
|
||||||
return Cc["@mozilla.org/network/protocol;1?name=http"]
|
return Cc["@mozilla.org/network/protocol;1?name=http"]
|
||||||
.getService(Ci.nsIHttpProtocolHandler).oscpu;
|
.getService(Ci.nsIHttpProtocolHandler).oscpu;
|
||||||
});
|
});
|
||||||
|
loader.lazyGetter(this, "is64Bit", () => {
|
||||||
XPCOMUtils.defineLazyGetter(this, "is64Bit", () => {
|
|
||||||
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).is64Bit;
|
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).is64Bit;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -79,8 +84,9 @@ const ToolboxButtons = exports.ToolboxButtons = [
|
||||||
target.getTrait("highlightable")
|
target.getTrait("highlightable")
|
||||||
},
|
},
|
||||||
{ id: "command-button-frames",
|
{ id: "command-button-frames",
|
||||||
isTargetSupported: target =>
|
isTargetSupported: target => {
|
||||||
( target.activeTab && target.activeTab.traits.frames )
|
return target.activeTab && target.activeTab.traits.frames;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{ id: "command-button-splitconsole",
|
{ id: "command-button-splitconsole",
|
||||||
isTargetSupported: target => !target.isAddon },
|
isTargetSupported: target => !target.isAddon },
|
||||||
|
@ -135,6 +141,7 @@ function Toolbox(target, selectedTool, hostType, hostOptions) {
|
||||||
this._onBottomHostMaximized = this._onBottomHostMaximized.bind(this);
|
this._onBottomHostMaximized = this._onBottomHostMaximized.bind(this);
|
||||||
this._onToolSelectWhileMinimized = this._onToolSelectWhileMinimized.bind(this);
|
this._onToolSelectWhileMinimized = this._onToolSelectWhileMinimized.bind(this);
|
||||||
this._onBottomHostWillChange = this._onBottomHostWillChange.bind(this);
|
this._onBottomHostWillChange = this._onBottomHostWillChange.bind(this);
|
||||||
|
this._toggleMinimizeMode = this._toggleMinimizeMode.bind(this);
|
||||||
|
|
||||||
this._target.on("close", this.destroy);
|
this._target.on("close", this.destroy);
|
||||||
|
|
||||||
|
@ -481,7 +488,7 @@ Toolbox.prototype = {
|
||||||
["toolbox-force-reload-key", true],
|
["toolbox-force-reload-key", true],
|
||||||
["toolbox-force-reload-key2", true]
|
["toolbox-force-reload-key2", true]
|
||||||
].forEach(([id, force]) => {
|
].forEach(([id, force]) => {
|
||||||
this.doc.getElementById(id).addEventListener("command", (event) => {
|
this.doc.getElementById(id).addEventListener("command", () => {
|
||||||
this.reloadTarget(force);
|
this.reloadTarget(force);
|
||||||
}, true);
|
}, true);
|
||||||
});
|
});
|
||||||
|
@ -493,6 +500,9 @@ Toolbox.prototype = {
|
||||||
let prevKey = this.doc.getElementById("toolbox-previous-tool-key");
|
let prevKey = this.doc.getElementById("toolbox-previous-tool-key");
|
||||||
prevKey.addEventListener("command", this.selectPreviousTool.bind(this), true);
|
prevKey.addEventListener("command", this.selectPreviousTool.bind(this), true);
|
||||||
|
|
||||||
|
let minimizeKey = this.doc.getElementById("toolbox-minimize-key");
|
||||||
|
minimizeKey.addEventListener("command", this._toggleMinimizeMode, true);
|
||||||
|
|
||||||
// Split console uses keypress instead of command so the event can be
|
// Split console uses keypress instead of command so the event can be
|
||||||
// cancelled with stopPropagation on the keypress, and not preventDefault.
|
// cancelled with stopPropagation on the keypress, and not preventDefault.
|
||||||
this.doc.addEventListener("keypress", this._splitConsoleOnKeypress, false);
|
this.doc.addEventListener("keypress", this._splitConsoleOnKeypress, false);
|
||||||
|
@ -703,18 +713,11 @@ Toolbox.prototype = {
|
||||||
if (this.hostType == Toolbox.HostType.BOTTOM) {
|
if (this.hostType == Toolbox.HostType.BOTTOM) {
|
||||||
let minimizeBtn = this.doc.createElement("toolbarbutton");
|
let minimizeBtn = this.doc.createElement("toolbarbutton");
|
||||||
minimizeBtn.id = "toolbox-dock-bottom-minimize";
|
minimizeBtn.id = "toolbox-dock-bottom-minimize";
|
||||||
minimizeBtn.className = "maximized";
|
|
||||||
minimizeBtn.setAttribute("tooltiptext",
|
minimizeBtn.addEventListener("command", this._toggleMinimizeMode);
|
||||||
toolboxStrings("toolboxDockButtons.bottom.minimize"));
|
|
||||||
// Calculate the height to which the host should be minimized so the
|
|
||||||
// tabbar is still visible.
|
|
||||||
let toolbarHeight = this.doc.querySelector(".devtools-tabbar")
|
|
||||||
.getBoxQuads({box: "content"})[0]
|
|
||||||
.bounds.height;
|
|
||||||
minimizeBtn.addEventListener("command", () => {
|
|
||||||
this._host.toggleMinimizeMode(toolbarHeight);
|
|
||||||
});
|
|
||||||
dockBox.appendChild(minimizeBtn);
|
dockBox.appendChild(minimizeBtn);
|
||||||
|
// Show the button in its maximized state.
|
||||||
|
this._onBottomHostMaximized();
|
||||||
|
|
||||||
// Update the label and icon when the state changes.
|
// Update the label and icon when the state changes.
|
||||||
this._host.on("minimized", this._onBottomHostMinimized);
|
this._host.on("minimized", this._onBottomHostMinimized);
|
||||||
|
@ -754,18 +757,29 @@ Toolbox.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_getMinimizeButtonShortcutTooltip: function() {
|
||||||
|
let key = this.doc.getElementById("toolbox-minimize-key")
|
||||||
|
.getAttribute("key");
|
||||||
|
return "(" + (osString == "Darwin" ? "Cmd+Shift+" : "Ctrl+Shift+") +
|
||||||
|
key.toUpperCase() + ")";
|
||||||
|
},
|
||||||
|
|
||||||
_onBottomHostMinimized: function() {
|
_onBottomHostMinimized: function() {
|
||||||
let btn = this.doc.querySelector("#toolbox-dock-bottom-minimize");
|
let btn = this.doc.querySelector("#toolbox-dock-bottom-minimize");
|
||||||
btn.className = "minimized";
|
btn.className = "minimized";
|
||||||
|
|
||||||
btn.setAttribute("tooltiptext",
|
btn.setAttribute("tooltiptext",
|
||||||
toolboxStrings("toolboxDockButtons.bottom.maximize"));
|
toolboxStrings("toolboxDockButtons.bottom.maximize") + " " +
|
||||||
|
this._getMinimizeButtonShortcutTooltip());
|
||||||
},
|
},
|
||||||
|
|
||||||
_onBottomHostMaximized: function() {
|
_onBottomHostMaximized: function() {
|
||||||
let btn = this.doc.querySelector("#toolbox-dock-bottom-minimize");
|
let btn = this.doc.querySelector("#toolbox-dock-bottom-minimize");
|
||||||
btn.className = "maximized";
|
btn.className = "maximized";
|
||||||
|
|
||||||
btn.setAttribute("tooltiptext",
|
btn.setAttribute("tooltiptext",
|
||||||
toolboxStrings("toolboxDockButtons.bottom.minimize"));
|
toolboxStrings("toolboxDockButtons.bottom.minimize") + " " +
|
||||||
|
this._getMinimizeButtonShortcutTooltip());
|
||||||
},
|
},
|
||||||
|
|
||||||
_onToolSelectWhileMinimized: function() {
|
_onToolSelectWhileMinimized: function() {
|
||||||
|
@ -780,6 +794,19 @@ Toolbox.prototype = {
|
||||||
this.off("before-select", this._onToolSelectWhileMinimized);
|
this.off("before-select", this._onToolSelectWhileMinimized);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_toggleMinimizeMode: function() {
|
||||||
|
if (this.hostType !== Toolbox.HostType.BOTTOM) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the height to which the host should be minimized so the
|
||||||
|
// tabbar is still visible.
|
||||||
|
let toolbarHeight = this.doc.querySelector(".devtools-tabbar")
|
||||||
|
.getBoxQuads({box: "content"})[0]
|
||||||
|
.bounds.height;
|
||||||
|
this._host.toggleMinimizeMode(toolbarHeight);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add tabs to the toolbox UI for registered tools
|
* Add tabs to the toolbox UI for registered tools
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -70,6 +70,10 @@
|
||||||
keycode="VK_F5"
|
keycode="VK_F5"
|
||||||
oncommand="void(0);"
|
oncommand="void(0);"
|
||||||
modifiers="accel"/>
|
modifiers="accel"/>
|
||||||
|
<key id="toolbox-minimize-key"
|
||||||
|
key="&toolboxToggleMinimize.key;"
|
||||||
|
oncommand="void(0);"
|
||||||
|
modifiers="shift, accel"/>
|
||||||
</keyset>
|
</keyset>
|
||||||
|
|
||||||
<popupset>
|
<popupset>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
const TEST_URL = TEST_URL_ROOT + "doc_markup_search.html";
|
const TEST_URL = TEST_URL_ROOT + "doc_markup_search.html";
|
||||||
|
|
||||||
add_task(function*() {
|
add_task(function*() {
|
||||||
let {inspector, toolbox} = yield addTab(TEST_URL).then(openInspector);
|
let {inspector} = yield addTab(TEST_URL).then(openInspector);
|
||||||
|
|
||||||
let container = yield getContainerForSelector("em", inspector);
|
let container = yield getContainerForSelector("em", inspector);
|
||||||
ok(!container, "The <em> tag isn't present yet in the markup-view");
|
ok(!container, "The <em> tag isn't present yet in the markup-view");
|
||||||
|
@ -19,11 +19,10 @@ add_task(function*() {
|
||||||
// Searching for the innermost element first makes sure that the inspector
|
// Searching for the innermost element first makes sure that the inspector
|
||||||
// back-end is able to attach the resulting node to the tree it knows at the
|
// back-end is able to attach the resulting node to the tree it knows at the
|
||||||
// moment. When the inspector is started, the <body> is the default selected
|
// moment. When the inspector is started, the <body> is the default selected
|
||||||
// node, and only the parents up to the ROOT are known, and its direct children
|
// node, and only the parents up to the ROOT are known, and its direct
|
||||||
|
// children.
|
||||||
info("searching for the innermost child: <em>");
|
info("searching for the innermost child: <em>");
|
||||||
let updated = inspector.once("inspector-updated");
|
yield searchFor("em", inspector);
|
||||||
searchUsingSelectorSearch("em", inspector);
|
|
||||||
yield updated;
|
|
||||||
|
|
||||||
container = yield getContainerForSelector("em", inspector);
|
container = yield getContainerForSelector("em", inspector);
|
||||||
ok(container, "The <em> tag is now imported in the markup-view");
|
ok(container, "The <em> tag is now imported in the markup-view");
|
||||||
|
@ -34,12 +33,19 @@ add_task(function*() {
|
||||||
|
|
||||||
info("searching for other nodes too");
|
info("searching for other nodes too");
|
||||||
for (let node of ["span", "li", "ul"]) {
|
for (let node of ["span", "li", "ul"]) {
|
||||||
let updated = inspector.once("inspector-updated");
|
yield searchFor(node, inspector);
|
||||||
searchUsingSelectorSearch(node, inspector);
|
|
||||||
yield updated;
|
|
||||||
|
|
||||||
nodeFront = yield getNodeFront(node, inspector);
|
nodeFront = yield getNodeFront(node, inspector);
|
||||||
is(inspector.selection.nodeFront, nodeFront,
|
is(inspector.selection.nodeFront, nodeFront,
|
||||||
"The <" + node + "> tag is the currently selected node");
|
"The <" + node + "> tag is the currently selected node");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function* searchFor(selector, inspector) {
|
||||||
|
let onNewNodeFront = inspector.selection.once("new-node-front");
|
||||||
|
|
||||||
|
searchUsingSelectorSearch(selector, inspector);
|
||||||
|
|
||||||
|
yield onNewNodeFront;
|
||||||
|
yield inspector.once("inspector-updated");
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,9 @@ const EVENTS = {
|
||||||
// more information about what each packet is supposed to deliver.
|
// more information about what each packet is supposed to deliver.
|
||||||
NETWORK_EVENT: "NetMonitor:NetworkEvent",
|
NETWORK_EVENT: "NetMonitor:NetworkEvent",
|
||||||
|
|
||||||
|
// When a network event is added to the view
|
||||||
|
REQUEST_ADDED: "NetMonitor:RequestAdded",
|
||||||
|
|
||||||
// When request headers begin and finish receiving.
|
// When request headers begin and finish receiving.
|
||||||
UPDATING_REQUEST_HEADERS: "NetMonitor:NetworkEventUpdating:RequestHeaders",
|
UPDATING_REQUEST_HEADERS: "NetMonitor:NetworkEventUpdating:RequestHeaders",
|
||||||
RECEIVED_REQUEST_HEADERS: "NetMonitor:NetworkEventUpdated:RequestHeaders",
|
RECEIVED_REQUEST_HEADERS: "NetMonitor:NetworkEventUpdated:RequestHeaders",
|
||||||
|
@ -528,34 +531,33 @@ NetworkEventsHandler.prototype = {
|
||||||
*/
|
*/
|
||||||
_onNetworkEventUpdate: function(type, { packet, networkInfo }) {
|
_onNetworkEventUpdate: function(type, { packet, networkInfo }) {
|
||||||
let { actor, request: { url } } = networkInfo;
|
let { actor, request: { url } } = networkInfo;
|
||||||
|
|
||||||
switch (packet.updateType) {
|
switch (packet.updateType) {
|
||||||
case "requestHeaders":
|
case "requestHeaders":
|
||||||
this.webConsoleClient.getRequestHeaders(actor, this._onRequestHeaders);
|
this.webConsoleClient.getRequestHeaders(actor, this._onRequestHeaders);
|
||||||
window.emit(EVENTS.UPDATING_REQUEST_HEADERS, [actor, url]);
|
window.emit(EVENTS.UPDATING_REQUEST_HEADERS, actor);
|
||||||
break;
|
break;
|
||||||
case "requestCookies":
|
case "requestCookies":
|
||||||
this.webConsoleClient.getRequestCookies(actor, this._onRequestCookies);
|
this.webConsoleClient.getRequestCookies(actor, this._onRequestCookies);
|
||||||
window.emit(EVENTS.UPDATING_REQUEST_COOKIES, [actor, url]);
|
window.emit(EVENTS.UPDATING_REQUEST_COOKIES, actor);
|
||||||
break;
|
break;
|
||||||
case "requestPostData":
|
case "requestPostData":
|
||||||
this.webConsoleClient.getRequestPostData(actor, this._onRequestPostData);
|
this.webConsoleClient.getRequestPostData(actor, this._onRequestPostData);
|
||||||
window.emit(EVENTS.UPDATING_REQUEST_POST_DATA, [actor, url]);
|
window.emit(EVENTS.UPDATING_REQUEST_POST_DATA, actor);
|
||||||
break;
|
break;
|
||||||
case "securityInfo":
|
case "securityInfo":
|
||||||
NetMonitorView.RequestsMenu.updateRequest(actor, {
|
NetMonitorView.RequestsMenu.updateRequest(actor, {
|
||||||
securityState: networkInfo.securityInfo,
|
securityState: networkInfo.securityInfo,
|
||||||
});
|
});
|
||||||
this.webConsoleClient.getSecurityInfo(actor, this._onSecurityInfo);
|
this.webConsoleClient.getSecurityInfo(actor, this._onSecurityInfo);
|
||||||
window.emit(EVENTS.UPDATING_SECURITY_INFO, [actor, url]);
|
window.emit(EVENTS.UPDATING_SECURITY_INFO, actor);
|
||||||
break;
|
break;
|
||||||
case "responseHeaders":
|
case "responseHeaders":
|
||||||
this.webConsoleClient.getResponseHeaders(actor, this._onResponseHeaders);
|
this.webConsoleClient.getResponseHeaders(actor, this._onResponseHeaders);
|
||||||
window.emit(EVENTS.UPDATING_RESPONSE_HEADERS, [actor, url]);
|
window.emit(EVENTS.UPDATING_RESPONSE_HEADERS, actor);
|
||||||
break;
|
break;
|
||||||
case "responseCookies":
|
case "responseCookies":
|
||||||
this.webConsoleClient.getResponseCookies(actor, this._onResponseCookies);
|
this.webConsoleClient.getResponseCookies(actor, this._onResponseCookies);
|
||||||
window.emit(EVENTS.UPDATING_RESPONSE_COOKIES, [actor, url]);
|
window.emit(EVENTS.UPDATING_RESPONSE_COOKIES, actor);
|
||||||
break;
|
break;
|
||||||
case "responseStart":
|
case "responseStart":
|
||||||
NetMonitorView.RequestsMenu.updateRequest(actor, {
|
NetMonitorView.RequestsMenu.updateRequest(actor, {
|
||||||
|
@ -566,7 +568,7 @@ NetworkEventsHandler.prototype = {
|
||||||
statusText: networkInfo.response.statusText,
|
statusText: networkInfo.response.statusText,
|
||||||
headersSize: networkInfo.response.headersSize
|
headersSize: networkInfo.response.headersSize
|
||||||
});
|
});
|
||||||
window.emit(EVENTS.STARTED_RECEIVING_RESPONSE, [actor, url]);
|
window.emit(EVENTS.STARTED_RECEIVING_RESPONSE, actor);
|
||||||
break;
|
break;
|
||||||
case "responseContent":
|
case "responseContent":
|
||||||
NetMonitorView.RequestsMenu.updateRequest(actor, {
|
NetMonitorView.RequestsMenu.updateRequest(actor, {
|
||||||
|
@ -575,14 +577,14 @@ NetworkEventsHandler.prototype = {
|
||||||
mimeType: networkInfo.response.content.mimeType
|
mimeType: networkInfo.response.content.mimeType
|
||||||
});
|
});
|
||||||
this.webConsoleClient.getResponseContent(actor, this._onResponseContent);
|
this.webConsoleClient.getResponseContent(actor, this._onResponseContent);
|
||||||
window.emit(EVENTS.UPDATING_RESPONSE_CONTENT, [actor, url]);
|
window.emit(EVENTS.UPDATING_RESPONSE_CONTENT, actor);
|
||||||
break;
|
break;
|
||||||
case "eventTimings":
|
case "eventTimings":
|
||||||
NetMonitorView.RequestsMenu.updateRequest(actor, {
|
NetMonitorView.RequestsMenu.updateRequest(actor, {
|
||||||
totalTime: networkInfo.totalTime
|
totalTime: networkInfo.totalTime
|
||||||
});
|
});
|
||||||
this.webConsoleClient.getEventTimings(actor, this._onEventTimings);
|
this.webConsoleClient.getEventTimings(actor, this._onEventTimings);
|
||||||
window.emit(EVENTS.UPDATING_EVENT_TIMINGS, [actor, url]);
|
window.emit(EVENTS.UPDATING_EVENT_TIMINGS, actor);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -596,8 +598,9 @@ NetworkEventsHandler.prototype = {
|
||||||
_onRequestHeaders: function(aResponse) {
|
_onRequestHeaders: function(aResponse) {
|
||||||
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
||||||
requestHeaders: aResponse
|
requestHeaders: aResponse
|
||||||
|
}, () => {
|
||||||
|
window.emit(EVENTS.RECEIVED_REQUEST_HEADERS, aResponse.from);
|
||||||
});
|
});
|
||||||
window.emit(EVENTS.RECEIVED_REQUEST_HEADERS, aResponse.from);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -609,8 +612,9 @@ NetworkEventsHandler.prototype = {
|
||||||
_onRequestCookies: function(aResponse) {
|
_onRequestCookies: function(aResponse) {
|
||||||
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
||||||
requestCookies: aResponse
|
requestCookies: aResponse
|
||||||
|
}, () => {
|
||||||
|
window.emit(EVENTS.RECEIVED_REQUEST_COOKIES, aResponse.from);
|
||||||
});
|
});
|
||||||
window.emit(EVENTS.RECEIVED_REQUEST_COOKIES, aResponse.from);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -622,8 +626,9 @@ NetworkEventsHandler.prototype = {
|
||||||
_onRequestPostData: function(aResponse) {
|
_onRequestPostData: function(aResponse) {
|
||||||
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
||||||
requestPostData: aResponse
|
requestPostData: aResponse
|
||||||
|
}, () => {
|
||||||
|
window.emit(EVENTS.RECEIVED_REQUEST_POST_DATA, aResponse.from);
|
||||||
});
|
});
|
||||||
window.emit(EVENTS.RECEIVED_REQUEST_POST_DATA, aResponse.from);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -635,9 +640,9 @@ NetworkEventsHandler.prototype = {
|
||||||
_onSecurityInfo: function(aResponse) {
|
_onSecurityInfo: function(aResponse) {
|
||||||
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
||||||
securityInfo: aResponse.securityInfo
|
securityInfo: aResponse.securityInfo
|
||||||
|
}, () => {
|
||||||
|
window.emit(EVENTS.RECEIVED_SECURITY_INFO, aResponse.from);
|
||||||
});
|
});
|
||||||
|
|
||||||
window.emit(EVENTS.RECEIVED_SECURITY_INFO, aResponse.from);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -649,8 +654,9 @@ NetworkEventsHandler.prototype = {
|
||||||
_onResponseHeaders: function(aResponse) {
|
_onResponseHeaders: function(aResponse) {
|
||||||
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
||||||
responseHeaders: aResponse
|
responseHeaders: aResponse
|
||||||
|
}, () => {
|
||||||
|
window.emit(EVENTS.RECEIVED_RESPONSE_HEADERS, aResponse.from);
|
||||||
});
|
});
|
||||||
window.emit(EVENTS.RECEIVED_RESPONSE_HEADERS, aResponse.from);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -662,8 +668,9 @@ NetworkEventsHandler.prototype = {
|
||||||
_onResponseCookies: function(aResponse) {
|
_onResponseCookies: function(aResponse) {
|
||||||
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
||||||
responseCookies: aResponse
|
responseCookies: aResponse
|
||||||
|
}, () => {
|
||||||
|
window.emit(EVENTS.RECEIVED_RESPONSE_COOKIES, aResponse.from);
|
||||||
});
|
});
|
||||||
window.emit(EVENTS.RECEIVED_RESPONSE_COOKIES, aResponse.from);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -675,8 +682,9 @@ NetworkEventsHandler.prototype = {
|
||||||
_onResponseContent: function(aResponse) {
|
_onResponseContent: function(aResponse) {
|
||||||
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
||||||
responseContent: aResponse
|
responseContent: aResponse
|
||||||
|
}, () => {
|
||||||
|
window.emit(EVENTS.RECEIVED_RESPONSE_CONTENT, aResponse.from);
|
||||||
});
|
});
|
||||||
window.emit(EVENTS.RECEIVED_RESPONSE_CONTENT, aResponse.from);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -688,8 +696,9 @@ NetworkEventsHandler.prototype = {
|
||||||
_onEventTimings: function(aResponse) {
|
_onEventTimings: function(aResponse) {
|
||||||
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
||||||
eventTimings: aResponse
|
eventTimings: aResponse
|
||||||
|
}, () => {
|
||||||
|
window.emit(EVENTS.RECEIVED_EVENT_TIMINGS, aResponse.from);
|
||||||
});
|
});
|
||||||
window.emit(EVENTS.RECEIVED_EVENT_TIMINGS, aResponse.from);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -75,6 +75,8 @@ const GENERIC_VARIABLES_VIEW_SETTINGS = {
|
||||||
const NETWORK_ANALYSIS_PIE_CHART_DIAMETER = 200; // px
|
const NETWORK_ANALYSIS_PIE_CHART_DIAMETER = 200; // px
|
||||||
const FREETEXT_FILTER_SEARCH_DELAY = 200; // ms
|
const FREETEXT_FILTER_SEARCH_DELAY = 200; // ms
|
||||||
|
|
||||||
|
const {DeferredTask} = Cu.import("resource://gre/modules/DeferredTask.jsm", {});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object defining the network monitor view components.
|
* Object defining the network monitor view components.
|
||||||
*/
|
*/
|
||||||
|
@ -95,6 +97,7 @@ let NetMonitorView = {
|
||||||
* Destroys the network monitor view.
|
* Destroys the network monitor view.
|
||||||
*/
|
*/
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
|
this._isDestroyed = true;
|
||||||
this.Toolbar.destroy();
|
this.Toolbar.destroy();
|
||||||
this.RequestsMenu.destroy();
|
this.RequestsMenu.destroy();
|
||||||
this.NetworkDetails.destroy();
|
this.NetworkDetails.destroy();
|
||||||
|
@ -375,7 +378,6 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||||
|
|
||||||
this.allowFocusOnRightClick = true;
|
this.allowFocusOnRightClick = true;
|
||||||
this.maintainSelectionVisible = true;
|
this.maintainSelectionVisible = true;
|
||||||
this.widget.autoscrollWithAppendedItems = true;
|
|
||||||
|
|
||||||
this.widget.addEventListener("select", this._onSelect, false);
|
this.widget.addEventListener("select", this._onSelect, false);
|
||||||
this.widget.addEventListener("swap", this._onSwap, false);
|
this.widget.addEventListener("swap", this._onSwap, false);
|
||||||
|
@ -394,6 +396,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||||
this._onContextToggleRawHeadersCommand = this.toggleRawHeaders.bind(this);
|
this._onContextToggleRawHeadersCommand = this.toggleRawHeaders.bind(this);
|
||||||
this._onContextPerfCommand = () => NetMonitorView.toggleFrontendMode();
|
this._onContextPerfCommand = () => NetMonitorView.toggleFrontendMode();
|
||||||
this._onReloadCommand = () => NetMonitorView.reloadPage();
|
this._onReloadCommand = () => NetMonitorView.reloadPage();
|
||||||
|
this._flushRequestsTask = new DeferredTask(this._flushRequests, REQUESTS_REFRESH_RATE);
|
||||||
|
|
||||||
this.sendCustomRequestEvent = this.sendCustomRequest.bind(this);
|
this.sendCustomRequestEvent = this.sendCustomRequest.bind(this);
|
||||||
this.closeCustomRequestEvent = this.closeCustomRequest.bind(this);
|
this.closeCustomRequestEvent = this.closeCustomRequest.bind(this);
|
||||||
|
@ -470,7 +473,10 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||||
$("#requests-menu-clear-button").removeEventListener("click", this.reqeustsMenuClearEvent, false);
|
$("#requests-menu-clear-button").removeEventListener("click", this.reqeustsMenuClearEvent, false);
|
||||||
this.freetextFilterBox.removeEventListener("input", this.requestsFreetextFilterEvent, false);
|
this.freetextFilterBox.removeEventListener("input", this.requestsFreetextFilterEvent, false);
|
||||||
this.freetextFilterBox.removeEventListener("command", this.requestsFreetextFilterEvent, false);
|
this.freetextFilterBox.removeEventListener("command", this.requestsFreetextFilterEvent, false);
|
||||||
|
|
||||||
this.userInputTimer.cancel();
|
this.userInputTimer.cancel();
|
||||||
|
this._flushRequestsTask.disarm();
|
||||||
|
|
||||||
$("#network-request-popup").removeEventListener("popupshowing", this._onContextShowing, false);
|
$("#network-request-popup").removeEventListener("popupshowing", this._onContextShowing, false);
|
||||||
$("#request-menu-context-newtab").removeEventListener("command", this._onContextNewTabCommand, false);
|
$("#request-menu-context-newtab").removeEventListener("command", this._onContextNewTabCommand, false);
|
||||||
$("#request-menu-context-copy-url").removeEventListener("command", this._onContextCopyUrlCommand, false);
|
$("#request-menu-context-copy-url").removeEventListener("command", this._onContextCopyUrlCommand, false);
|
||||||
|
@ -496,6 +502,8 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||||
*/
|
*/
|
||||||
reset: function() {
|
reset: function() {
|
||||||
this.empty();
|
this.empty();
|
||||||
|
this._addQueue = [];
|
||||||
|
this._updateQueue = [];
|
||||||
this._firstRequestStartedMillis = -1;
|
this._firstRequestStartedMillis = -1;
|
||||||
this._lastRequestEndedMillis = -1;
|
this._lastRequestEndedMillis = -1;
|
||||||
},
|
},
|
||||||
|
@ -503,7 +511,18 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||||
/**
|
/**
|
||||||
* Specifies if this view may be updated lazily.
|
* Specifies if this view may be updated lazily.
|
||||||
*/
|
*/
|
||||||
lazyUpdate: true,
|
_lazyUpdate: true,
|
||||||
|
|
||||||
|
get lazyUpdate() {
|
||||||
|
return this._lazyUpdate;
|
||||||
|
},
|
||||||
|
|
||||||
|
set lazyUpdate(value) {
|
||||||
|
this._lazyUpdate = value;
|
||||||
|
if (!value) {
|
||||||
|
this._flushRequests();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a network request to this container.
|
* Adds a network request to this container.
|
||||||
|
@ -523,47 +542,14 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||||
* Indicates if the result came from the browser cache
|
* Indicates if the result came from the browser cache
|
||||||
*/
|
*/
|
||||||
addRequest: function(aId, aStartedDateTime, aMethod, aUrl, aIsXHR, aFromCache) {
|
addRequest: function(aId, aStartedDateTime, aMethod, aUrl, aIsXHR, aFromCache) {
|
||||||
// Convert the received date/time string to a unix timestamp.
|
this._addQueue.push([aId, aStartedDateTime, aMethod, aUrl, aIsXHR, aFromCache]);
|
||||||
let unixTime = Date.parse(aStartedDateTime);
|
|
||||||
|
|
||||||
// Create the element node for the network request item.
|
// Lazy updating is disabled in some tests.
|
||||||
let menuView = this._createMenuView(aMethod, aUrl);
|
if (!this.lazyUpdate) {
|
||||||
|
return void this._flushRequests();
|
||||||
// Remember the first and last event boundaries.
|
|
||||||
this._registerFirstRequestStart(unixTime);
|
|
||||||
this._registerLastRequestEnd(unixTime);
|
|
||||||
|
|
||||||
// Append a network request item to this container.
|
|
||||||
let requestItem = this.push([menuView, aId], {
|
|
||||||
attachment: {
|
|
||||||
startedDeltaMillis: unixTime - this._firstRequestStartedMillis,
|
|
||||||
startedMillis: unixTime,
|
|
||||||
method: aMethod,
|
|
||||||
url: aUrl,
|
|
||||||
isXHR: aIsXHR,
|
|
||||||
fromCache: aFromCache
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a tooltip for the newly appended network request item.
|
|
||||||
let requestTooltip = requestItem.attachment.tooltip = new Tooltip(document, {
|
|
||||||
closeOnEvents: [{
|
|
||||||
emitter: $("#requests-menu-contents"),
|
|
||||||
event: "scroll",
|
|
||||||
useCapture: true
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#details-pane-toggle").disabled = false;
|
|
||||||
$("#requests-menu-empty-notice").hidden = true;
|
|
||||||
|
|
||||||
this.refreshSummary();
|
|
||||||
this.refreshZebra();
|
|
||||||
this.refreshTooltip(requestItem);
|
|
||||||
|
|
||||||
if (aId == this._preferredItemId) {
|
|
||||||
this.selectedItem = requestItem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._flushRequestsTask.arm();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1326,30 +1312,80 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||||
* @param object aData
|
* @param object aData
|
||||||
* An object containing several { key: value } tuples of network info.
|
* An object containing several { key: value } tuples of network info.
|
||||||
* Supported keys are "httpVersion", "status", "statusText" etc.
|
* Supported keys are "httpVersion", "status", "statusText" etc.
|
||||||
|
* @param function aCallback
|
||||||
|
* A function to call once the request has been updated in the view.
|
||||||
*/
|
*/
|
||||||
updateRequest: function(aId, aData) {
|
updateRequest: function(aId, aData, aCallback) {
|
||||||
// Prevent interference from zombie updates received after target closed.
|
this._updateQueue.push([aId, aData, aCallback]);
|
||||||
if (NetMonitorView._isDestroyed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._updateQueue.push([aId, aData]);
|
|
||||||
|
|
||||||
// Lazy updating is disabled in some tests.
|
// Lazy updating is disabled in some tests.
|
||||||
if (!this.lazyUpdate) {
|
if (!this.lazyUpdate) {
|
||||||
return void this._flushRequests();
|
return void this._flushRequests();
|
||||||
}
|
}
|
||||||
// Allow requests to settle down first.
|
|
||||||
setNamedTimeout(
|
this._flushRequestsTask.arm();
|
||||||
"update-requests", REQUESTS_REFRESH_RATE, () => this._flushRequests());
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts adding all queued additional information about network requests.
|
* Starts adding all queued additional information about network requests.
|
||||||
*/
|
*/
|
||||||
_flushRequests: function() {
|
_flushRequests: function() {
|
||||||
|
// Prevent displaying any updates received after the target closed.
|
||||||
|
if (NetMonitorView._isDestroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let widget = NetMonitorView.RequestsMenu.widget;
|
||||||
|
let isScrolledToBottom = widget.isScrolledToBottom();
|
||||||
|
|
||||||
|
for (let [id, startedDateTime, method, url, isXHR, fromCache] of this._addQueue) {
|
||||||
|
// Convert the received date/time string to a unix timestamp.
|
||||||
|
let unixTime = Date.parse(startedDateTime);
|
||||||
|
|
||||||
|
// Create the element node for the network request item.
|
||||||
|
let menuView = this._createMenuView(method, url);
|
||||||
|
|
||||||
|
// Remember the first and last event boundaries.
|
||||||
|
this._registerFirstRequestStart(unixTime);
|
||||||
|
this._registerLastRequestEnd(unixTime);
|
||||||
|
|
||||||
|
// Append a network request item to this container.
|
||||||
|
let requestItem = this.push([menuView, id], {
|
||||||
|
attachment: {
|
||||||
|
startedDeltaMillis: unixTime - this._firstRequestStartedMillis,
|
||||||
|
startedMillis: unixTime,
|
||||||
|
method: method,
|
||||||
|
url: url,
|
||||||
|
isXHR: isXHR,
|
||||||
|
fromCache: fromCache
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create a tooltip for the newly appended network request item.
|
||||||
|
let requestTooltip = requestItem.attachment.tooltip = new Tooltip(document, {
|
||||||
|
closeOnEvents: [{
|
||||||
|
emitter: $("#requests-menu-contents"),
|
||||||
|
event: "scroll",
|
||||||
|
useCapture: true
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
this.refreshTooltip(requestItem);
|
||||||
|
|
||||||
|
if (id == this._preferredItemId) {
|
||||||
|
this.selectedItem = requestItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.emit(EVENTS.REQUEST_ADDED, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isScrolledToBottom && this._addQueue.length) {
|
||||||
|
widget.scrollToBottom();
|
||||||
|
}
|
||||||
|
|
||||||
// For each queued additional information packet, get the corresponding
|
// For each queued additional information packet, get the corresponding
|
||||||
// request item in the view and update it based on the specified data.
|
// request item in the view and update it based on the specified data.
|
||||||
for (let [id, data] of this._updateQueue) {
|
for (let [id, data, callback] of this._updateQueue) {
|
||||||
let requestItem = this.getItemByValue(id);
|
let requestItem = this.getItemByValue(id);
|
||||||
if (!requestItem) {
|
if (!requestItem) {
|
||||||
// Packet corresponds to a dead request item, target navigated.
|
// Packet corresponds to a dead request item, target navigated.
|
||||||
|
@ -1482,6 +1518,10 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
refreshNetworkDetailsPaneIfNecessary(requestItem);
|
refreshNetworkDetailsPaneIfNecessary(requestItem);
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1502,6 +1542,10 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||||
|
|
||||||
// We're done flushing all the requests, clear the update queue.
|
// We're done flushing all the requests, clear the update queue.
|
||||||
this._updateQueue = [];
|
this._updateQueue = [];
|
||||||
|
this._addQueue = [];
|
||||||
|
|
||||||
|
$("#details-pane-toggle").disabled = !this.itemCount;
|
||||||
|
$("#requests-menu-empty-notice").hidden = !!this.itemCount;
|
||||||
|
|
||||||
// Make sure all the requests are sorted and filtered.
|
// Make sure all the requests are sorted and filtered.
|
||||||
// Freshly added requests may not yet contain all the information required
|
// Freshly added requests may not yet contain all the information required
|
||||||
|
@ -1650,9 +1694,9 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||||
}
|
}
|
||||||
case "responseContent": {
|
case "responseContent": {
|
||||||
let { mimeType } = aItem.attachment;
|
let { mimeType } = aItem.attachment;
|
||||||
let { text, encoding } = aValue.content;
|
|
||||||
|
|
||||||
if (mimeType.includes("image/")) {
|
if (mimeType.includes("image/")) {
|
||||||
|
let { text, encoding } = aValue.content;
|
||||||
let responseBody = yield gNetwork.getString(text);
|
let responseBody = yield gNetwork.getString(text);
|
||||||
let node = $(".requests-menu-icon", aItem.target);
|
let node = $(".requests-menu-icon", aItem.target);
|
||||||
node.src = "data:" + mimeType + ";" + encoding + "," + responseBody;
|
node.src = "data:" + mimeType + ";" + encoding + "," + responseBody;
|
||||||
|
@ -2158,6 +2202,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||||
_firstRequestStartedMillis: -1,
|
_firstRequestStartedMillis: -1,
|
||||||
_lastRequestEndedMillis: -1,
|
_lastRequestEndedMillis: -1,
|
||||||
_updateQueue: [],
|
_updateQueue: [],
|
||||||
|
_addQueue: [],
|
||||||
_updateTimeout: null,
|
_updateTimeout: null,
|
||||||
_resizeTimeout: null,
|
_resizeTimeout: null,
|
||||||
_activeFilters: ["all"],
|
_activeFilters: ["all"],
|
||||||
|
|
|
@ -95,6 +95,11 @@ let test = Task.async(function* () {
|
||||||
info("Waiting for NETWORK_EVENT");
|
info("Waiting for NETWORK_EVENT");
|
||||||
yield onNetworkEvent;
|
yield onNetworkEvent;
|
||||||
|
|
||||||
|
if (!RequestsMenu.getItemAtIndex(0)) {
|
||||||
|
info("Waiting for the request to be added to the view")
|
||||||
|
yield monitor.panelWin.once(monitor.panelWin.EVENTS.REQUEST_ADDED);
|
||||||
|
}
|
||||||
|
|
||||||
ok(true, "Received NETWORK_EVENT. Selecting the item.");
|
ok(true, "Received NETWORK_EVENT. Selecting the item.");
|
||||||
let item = RequestsMenu.getItemAtIndex(0);
|
let item = RequestsMenu.getItemAtIndex(0);
|
||||||
RequestsMenu.selectedItem = item;
|
RequestsMenu.selectedItem = item;
|
||||||
|
|
|
@ -240,20 +240,24 @@ function waitForNetworkEvents(aMonitor, aGetRequests, aPostRequests = 0) {
|
||||||
maybeResolve(event, actor);
|
maybeResolve(event, actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybeResolve(event, [actor, url]) {
|
function maybeResolve(event, actor) {
|
||||||
info("> Network events progress: " +
|
info("> Network events progress: " +
|
||||||
genericEvents + "/" + ((aGetRequests + aPostRequests) * 13) + ", " +
|
genericEvents + "/" + ((aGetRequests + aPostRequests) * 13) + ", " +
|
||||||
postEvents + "/" + (aPostRequests * 2) + ", " +
|
postEvents + "/" + (aPostRequests * 2) + ", " +
|
||||||
"got " + event + " for " + actor);
|
"got " + event + " for " + actor);
|
||||||
|
|
||||||
|
let networkInfo =
|
||||||
|
panel.NetMonitorController.webConsoleClient.getNetworkRequest(actor)
|
||||||
|
let url = networkInfo.request.url;
|
||||||
updateProgressForURL(url, event);
|
updateProgressForURL(url, event);
|
||||||
|
|
||||||
info("> Current state: " + JSON.stringify(progress, null, 2));
|
info("> Current state: " + JSON.stringify(progress, null, 2));
|
||||||
|
|
||||||
// There are 15 updates which need to be fired for a request to be
|
// There are 15 updates which need to be fired for a request to be
|
||||||
// considered finished. The "requestPostData" packet isn't fired for
|
// considered finished. The "requestPostData" packet isn't fired for
|
||||||
// non-POST requests.
|
// non-POST requests.
|
||||||
if (genericEvents == (aGetRequests + aPostRequests) * 13 &&
|
if (genericEvents >= (aGetRequests + aPostRequests) * 13 &&
|
||||||
postEvents == aPostRequests * 2) {
|
postEvents >= aPostRequests * 2) {
|
||||||
|
|
||||||
awaitedEventsToListeners.forEach(([e, l]) => panel.off(events[e], l));
|
awaitedEventsToListeners.forEach(([e, l]) => panel.off(events[e], l));
|
||||||
executeSoon(deferred.resolve);
|
executeSoon(deferred.resolve);
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
* Tests that the js call tree view renders the correct columns.
|
* Tests that the js call tree view renders the correct columns.
|
||||||
*/
|
*/
|
||||||
function* spawnTest() {
|
function* spawnTest() {
|
||||||
|
// This test seems to take a long time to cleanup on Ubuntu VMs.
|
||||||
|
requestLongerTimeout(2);
|
||||||
|
|
||||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||||
let { EVENTS, $, $$, DetailsView, JsCallTreeView } = panel.panelWin;
|
let { EVENTS, $, $$, DetailsView, JsCallTreeView } = panel.panelWin;
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ function* spawnTest() {
|
||||||
busyWait(WAIT_TIME); // allow the profiler module to sample some cpu activity
|
busyWait(WAIT_TIME); // allow the profiler module to sample some cpu activity
|
||||||
|
|
||||||
yield front.stopRecording(firstRecording);
|
yield front.stopRecording(firstRecording);
|
||||||
|
info("The first recording is " + firstRecording.getDuration() + "ms long.");
|
||||||
|
|
||||||
is(firstRecordingStartTime, 0,
|
is(firstRecordingStartTime, 0,
|
||||||
"The profiling start time should be 0 for the first recording.");
|
"The profiling start time should be 0 for the first recording.");
|
||||||
|
@ -50,6 +51,8 @@ function* spawnTest() {
|
||||||
busyWait(WAIT_TIME); // allow the profiler module to sample more cpu activity
|
busyWait(WAIT_TIME); // allow the profiler module to sample more cpu activity
|
||||||
|
|
||||||
yield front.stopRecording(secondRecording);
|
yield front.stopRecording(secondRecording);
|
||||||
|
info("The second recording is " + secondRecording.getDuration() + "ms long.");
|
||||||
|
|
||||||
let secondRecordingProfile = secondRecording.getProfile();
|
let secondRecordingProfile = secondRecording.getProfile();
|
||||||
let secondRecordingSamples = secondRecordingProfile.threads[0].samples.data;
|
let secondRecordingSamples = secondRecordingProfile.threads[0].samples.data;
|
||||||
|
|
||||||
|
|
|
@ -24,64 +24,63 @@ function testRecordings (win, expected) {
|
||||||
function* spawnTest() {
|
function* spawnTest() {
|
||||||
loadFrameScripts();
|
loadFrameScripts();
|
||||||
let { target, toolbox, panel } = yield initPerformance(SIMPLE_URL);
|
let { target, toolbox, panel } = yield initPerformance(SIMPLE_URL);
|
||||||
let win = panel.panelWin;
|
let { EVENTS, PerformanceController, OverviewView, RecordingsView, WaterfallView } = panel.panelWin;
|
||||||
let { $, EVENTS, gFront, PerformanceController, OverviewView, RecordingsView, WaterfallView } = win;
|
|
||||||
|
|
||||||
info("Starting console.profile()...");
|
info("Starting console.profile()...");
|
||||||
yield consoleProfile(win);
|
yield consoleProfile(panel.panelWin);
|
||||||
testRecordings(win, [C+S+R]);
|
testRecordings(panel.panelWin, [C+S+R]);
|
||||||
info("Starting manual recording...");
|
info("Starting manual recording...");
|
||||||
yield startRecording(panel);
|
yield startRecording(panel);
|
||||||
testRecordings(win, [C+R, R+S]);
|
testRecordings(panel.panelWin, [C+R, R+S]);
|
||||||
info("Starting console.profile(\"3\")...");
|
info("Starting console.profile(\"3\")...");
|
||||||
yield consoleProfile(win, "3");
|
yield consoleProfile(panel.panelWin, "3");
|
||||||
testRecordings(win, [C+R, R+S, C+R]);
|
testRecordings(panel.panelWin, [C+R, R+S, C+R]);
|
||||||
info("Starting console.profile(\"3\")...");
|
info("Starting console.profile(\"3\")...");
|
||||||
yield consoleProfile(win, "4");
|
yield consoleProfile(panel.panelWin, "4");
|
||||||
testRecordings(win, [C+R, R+S, C+R, C+R]);
|
testRecordings(panel.panelWin, [C+R, R+S, C+R, C+R]);
|
||||||
|
|
||||||
info("Ending console.profileEnd()...");
|
info("Ending console.profileEnd()...");
|
||||||
yield consoleProfileEnd(win);
|
yield consoleProfileEnd(panel.panelWin);
|
||||||
|
|
||||||
testRecordings(win, [C+R, R+S, C+R, C]);
|
testRecordings(panel.panelWin, [C+R, R+S, C+R, C]);
|
||||||
ok(OverviewView.isRendering(), "still rendering overview with manual recorded selected.");
|
ok(OverviewView.isRendering(), "still rendering overview with manual recorded selected.");
|
||||||
|
|
||||||
let onSelected = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
|
let onSelected = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
|
||||||
info("Select last recording...");
|
info("Select last recording...");
|
||||||
RecordingsView.selectedIndex = 3;
|
RecordingsView.selectedIndex = 3;
|
||||||
yield onSelected;
|
yield onSelected;
|
||||||
testRecordings(win, [C+R, R, C+R, C+S]);
|
testRecordings(panel.panelWin, [C+R, R, C+R, C+S]);
|
||||||
ok(!OverviewView.isRendering(), "stop rendering overview when selected completed recording.");
|
ok(!OverviewView.isRendering(), "stop rendering overview when selected completed recording.");
|
||||||
|
|
||||||
info("Manually stop manual recording...");
|
info("Manually stop manual recording...");
|
||||||
yield stopRecording(panel);
|
yield stopRecording(panel);
|
||||||
testRecordings(win, [C+R, S, C+R, C]);
|
testRecordings(panel.panelWin, [C+R, S, C+R, C]);
|
||||||
ok(!OverviewView.isRendering(), "stop rendering overview when selected completed recording.");
|
ok(!OverviewView.isRendering(), "stop rendering overview when selected completed recording.");
|
||||||
|
|
||||||
onSelected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
|
onSelected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
|
||||||
info("Select first recording...");
|
info("Select first recording...");
|
||||||
RecordingsView.selectedIndex = 0;
|
RecordingsView.selectedIndex = 0;
|
||||||
yield onSelected;
|
yield onSelected;
|
||||||
testRecordings(win, [C+R+S, 0, C+R, C]);
|
testRecordings(panel.panelWin, [C+R+S, 0, C+R, C]);
|
||||||
yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
|
yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
|
||||||
ok(OverviewView.isRendering(), "should be rendering overview when selected recording in progress.");
|
ok(OverviewView.isRendering(), "should be rendering overview when selected recording in progress.");
|
||||||
|
|
||||||
info("Ending console.profileEnd()...");
|
info("Ending console.profileEnd()...");
|
||||||
yield consoleProfileEnd(win);
|
yield consoleProfileEnd(panel.panelWin);
|
||||||
testRecordings(win, [C+R+S, 0, C, C]);
|
testRecordings(panel.panelWin, [C+R+S, 0, C, C]);
|
||||||
ok(OverviewView.isRendering(), "should still be rendering overview when selected recording in progress.");
|
ok(OverviewView.isRendering(), "should still be rendering overview when selected recording in progress.");
|
||||||
info("Start one more manual recording...");
|
info("Start one more manual recording...");
|
||||||
yield startRecording(panel);
|
yield startRecording(panel);
|
||||||
testRecordings(win, [C+R, 0, C, C, R+S]);
|
testRecordings(panel.panelWin, [C+R, 0, C, C, R+S]);
|
||||||
ok(OverviewView.isRendering(), "should be rendering overview when selected recording in progress.");
|
ok(OverviewView.isRendering(), "should be rendering overview when selected recording in progress.");
|
||||||
info("Stop manual recording...");
|
info("Stop manual recording...");
|
||||||
yield stopRecording(panel);
|
yield stopRecording(panel);
|
||||||
testRecordings(win, [C+R, 0, C, C, S]);
|
testRecordings(panel.panelWin, [C+R, 0, C, C, S]);
|
||||||
ok(!OverviewView.isRendering(), "stop rendering overview when selected completed recording.");
|
ok(!OverviewView.isRendering(), "stop rendering overview when selected completed recording.");
|
||||||
|
|
||||||
info("Ending console.profileEnd()...");
|
info("Ending console.profileEnd()...");
|
||||||
yield consoleProfileEnd(win);
|
yield consoleProfileEnd(panel.panelWin);
|
||||||
testRecordings(win, [C, 0, C, C, S]);
|
testRecordings(panel.panelWin, [C, 0, C, C, S]);
|
||||||
ok(!OverviewView.isRendering(), "stop rendering overview when selected completed recording.");
|
ok(!OverviewView.isRendering(), "stop rendering overview when selected completed recording.");
|
||||||
|
|
||||||
yield teardown(panel);
|
yield teardown(panel);
|
||||||
|
|
|
@ -7,9 +7,8 @@
|
||||||
|
|
||||||
function* spawnTest() {
|
function* spawnTest() {
|
||||||
let { target, panel } = yield initPerformance(SIMPLE_URL);
|
let { target, panel } = yield initPerformance(SIMPLE_URL);
|
||||||
let { $, $$, EVENTS, PerformanceController, OverviewView, WaterfallView } = panel.panelWin;
|
let { $, $$, PerformanceController, WaterfallView } = panel.panelWin;
|
||||||
let { L10N } = devtools.require("devtools/performance/global");
|
let { L10N } = devtools.require("devtools/performance/global");
|
||||||
let { TIMELINE_BLUEPRINT } = devtools.require("devtools/performance/markers");
|
|
||||||
let { getMarkerLabel } = devtools.require("devtools/performance/marker-utils");
|
let { getMarkerLabel } = devtools.require("devtools/performance/marker-utils");
|
||||||
|
|
||||||
// Hijack the markers massaging part of creating the waterfall view,
|
// Hijack the markers massaging part of creating the waterfall view,
|
||||||
|
@ -34,38 +33,35 @@ function* spawnTest() {
|
||||||
yield stopRecording(panel);
|
yield stopRecording(panel);
|
||||||
ok(true, "Recording has ended.");
|
ok(true, "Recording has ended.");
|
||||||
|
|
||||||
// Select everything
|
|
||||||
let timeline = OverviewView.graphs.get("timeline");
|
|
||||||
let rerendered = WaterfallView.once(EVENTS.WATERFALL_RENDERED);
|
|
||||||
timeline.setSelection({ start: 0, end: timeline.width })
|
|
||||||
yield rerendered;
|
|
||||||
|
|
||||||
let bars = $$(".waterfall-marker-bar");
|
let bars = $$(".waterfall-marker-bar");
|
||||||
let markers = PerformanceController.getCurrentRecording().getMarkers();
|
let markers = PerformanceController.getCurrentRecording().getMarkers();
|
||||||
|
|
||||||
ok(bars.length > 2, "Got at least 3 markers (1)");
|
ok(bars.length > 2, "Got at least 3 markers (1)");
|
||||||
ok(markers.length > 2, "Got at least 3 markers (2)");
|
ok(markers.length > 2, "Got at least 3 markers (2)");
|
||||||
|
|
||||||
|
let toMs = ms => L10N.getFormatStrWithNumbers("timeline.tick", ms);
|
||||||
|
|
||||||
for (let i = 0; i < bars.length; i++) {
|
for (let i = 0; i < bars.length; i++) {
|
||||||
let bar = bars[i];
|
let bar = bars[i];
|
||||||
let m = markers[i];
|
let mkr = markers[i];
|
||||||
EventUtils.sendMouseEvent({ type: "mousedown" }, bar);
|
EventUtils.sendMouseEvent({ type: "mousedown" }, bar);
|
||||||
|
|
||||||
is($("#waterfall-details .marker-details-type").getAttribute("value"), getMarkerLabel(m),
|
let type = $(".marker-details-type").getAttribute("value");
|
||||||
"Sidebar title matches markers name.");
|
|
||||||
|
|
||||||
let tooltip = $(".marker-details-duration").getAttribute("tooltiptext");
|
let tooltip = $(".marker-details-duration").getAttribute("tooltiptext");
|
||||||
let duration = $(".marker-details-duration .marker-details-labelvalue").getAttribute("value");
|
let duration = $(".marker-details-duration .marker-details-labelvalue").getAttribute("value");
|
||||||
|
|
||||||
let toMs = ms => L10N.getFormatStrWithNumbers("timeline.tick", ms);
|
info("Current marker data: " + mkr.toSource());
|
||||||
|
info("Current marker output: " + $("#waterfall-details").innerHTML);
|
||||||
|
|
||||||
|
is(type, getMarkerLabel(mkr), "Sidebar title matches markers name.");
|
||||||
|
|
||||||
// Values are rounded. We don't use a strict equality.
|
// Values are rounded. We don't use a strict equality.
|
||||||
is(toMs(m.end - m.start), duration, "Sidebar duration is valid.");
|
is(toMs(mkr.end - mkr.start), duration, "Sidebar duration is valid.");
|
||||||
|
|
||||||
// For some reason, anything that creates "→" here turns it into a "â" for some reason.
|
// For some reason, anything that creates "→" here turns it into a "â" for some reason.
|
||||||
// So just check that start and end time are in there somewhere.
|
// So just check that start and end time are in there somewhere.
|
||||||
ok(tooltip.indexOf(toMs(m.start)) !== -1, "Tooltip has start time.");
|
ok(tooltip.indexOf(toMs(mkr.start)) !== -1, "Tooltip has start time.");
|
||||||
ok(tooltip.indexOf(toMs(m.end)) !== -1, "Tooltip has end time.");
|
ok(tooltip.indexOf(toMs(mkr.end)) !== -1, "Tooltip has end time.");
|
||||||
}
|
}
|
||||||
|
|
||||||
yield teardown(panel);
|
yield teardown(panel);
|
||||||
|
|
|
@ -10,12 +10,9 @@ const Cu = Components.utils;
|
||||||
|
|
||||||
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
||||||
Cu.import("resource://gre/modules/devtools/event-emitter.js");
|
Cu.import("resource://gre/modules/devtools/event-emitter.js");
|
||||||
const {DeferredTask} = Cu.import("resource://gre/modules/DeferredTask.jsm", {});
|
|
||||||
|
|
||||||
this.EXPORTED_SYMBOLS = ["SideMenuWidget"];
|
this.EXPORTED_SYMBOLS = ["SideMenuWidget"];
|
||||||
|
|
||||||
const SCROLL_FREQUENCY = 16;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple side menu, with the ability of grouping menu items.
|
* A simple side menu, with the ability of grouping menu items.
|
||||||
*
|
*
|
||||||
|
@ -81,14 +78,6 @@ SideMenuWidget.prototype = {
|
||||||
*/
|
*/
|
||||||
groupSortPredicate: function(a, b) a.localeCompare(b),
|
groupSortPredicate: function(a, b) a.localeCompare(b),
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies that the container viewport should be "stuck" to the
|
|
||||||
* bottom. That is, the container is automatically scrolled down to
|
|
||||||
* keep appended items visible, but only when the scroll position is
|
|
||||||
* already at the bottom.
|
|
||||||
*/
|
|
||||||
autoscrollWithAppendedItems: false,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts an item in this container at the specified index, optionally
|
* Inserts an item in this container at the specified index, optionally
|
||||||
* grouping by name.
|
* grouping by name.
|
||||||
|
@ -106,29 +95,10 @@ SideMenuWidget.prototype = {
|
||||||
* The element associated with the displayed item.
|
* The element associated with the displayed item.
|
||||||
*/
|
*/
|
||||||
insertItemAt: function(aIndex, aContents, aAttachment={}) {
|
insertItemAt: function(aIndex, aContents, aAttachment={}) {
|
||||||
// Maintaining scroll position at the bottom when a new item is inserted
|
|
||||||
// depends on several factors (the order of testing is important to avoid
|
|
||||||
// needlessly expensive operations that may cause reflows):
|
|
||||||
let maintainScrollAtBottom =
|
|
||||||
// 1. The behavior should be enabled,
|
|
||||||
this.autoscrollWithAppendedItems &&
|
|
||||||
// 2. There shouldn't currently be any selected item in the list.
|
|
||||||
!this._selectedItem &&
|
|
||||||
// 3. The new item should be appended at the end of the list.
|
|
||||||
(aIndex < 0 || aIndex >= this._orderedMenuElementsArray.length) &&
|
|
||||||
// 4. We aren't waiting for a scroll to happen.
|
|
||||||
(!this._scrollToBottomTask || !this._scrollToBottomTask.isArmed) &&
|
|
||||||
// 5. The list should already be scrolled at the bottom.
|
|
||||||
this.isScrolledToBottom();
|
|
||||||
|
|
||||||
let group = this._getMenuGroupForName(aAttachment.group);
|
let group = this._getMenuGroupForName(aAttachment.group);
|
||||||
let item = this._getMenuItemForGroup(group, aContents, aAttachment);
|
let item = this._getMenuItemForGroup(group, aContents, aAttachment);
|
||||||
let element = item.insertSelfAt(aIndex);
|
let element = item.insertSelfAt(aIndex);
|
||||||
|
|
||||||
if (maintainScrollAtBottom) {
|
|
||||||
this.scrollToBottom();
|
|
||||||
}
|
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -158,30 +128,8 @@ SideMenuWidget.prototype = {
|
||||||
* If the user scrolls in the meantime, cancel this operation.
|
* If the user scrolls in the meantime, cancel this operation.
|
||||||
*/
|
*/
|
||||||
scrollToBottom: function() {
|
scrollToBottom: function() {
|
||||||
// Lazily attach this functionality to the object, so it won't get
|
this._list.scrollTop = this._list.scrollHeight;
|
||||||
// created unless if this scrollToBottom behavior is needed.
|
this.emit("scroll-to-bottom");
|
||||||
if (!this._scrollToBottomTask) {
|
|
||||||
// The scroll event fires asynchronously, so we need to keep a bit to
|
|
||||||
// distinguish between user-initiated events and scrollTop assignment.
|
|
||||||
let ignoreNextScroll = false;
|
|
||||||
|
|
||||||
this._scrollToBottomTask = new DeferredTask(() => {
|
|
||||||
ignoreNextScroll = true;
|
|
||||||
this._list.scrollTop = this._list.scrollHeight;
|
|
||||||
this.emit("scroll-to-bottom");
|
|
||||||
}, SCROLL_FREQUENCY);
|
|
||||||
|
|
||||||
// On a user scroll, cancel any pending calls to the scroll function.
|
|
||||||
this._list.addEventListener("scroll", () => {
|
|
||||||
if (!ignoreNextScroll && this._scrollToBottomTask.isArmed &&
|
|
||||||
!this.isScrolledToBottom()) {
|
|
||||||
this._scrollToBottomTask.disarm();
|
|
||||||
}
|
|
||||||
ignoreNextScroll = false;
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._scrollToBottomTask.arm();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,6 +17,7 @@ add_task(function*() {
|
||||||
let target = TargetFactory.forTab(tab);
|
let target = TargetFactory.forTab(tab);
|
||||||
let toolbox = yield gDevTools.showToolbox(target, "netmonitor");
|
let toolbox = yield gDevTools.showToolbox(target, "netmonitor");
|
||||||
let netmonitor = toolbox.getPanel("netmonitor");
|
let netmonitor = toolbox.getPanel("netmonitor");
|
||||||
|
netmonitor._view.RequestsMenu.lazyUpdate = false;
|
||||||
|
|
||||||
info("Navigating to test page");
|
info("Navigating to test page");
|
||||||
yield navigateTo(TEST_URL);
|
yield navigateTo(TEST_URL);
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- TODO : Bug 1165122 : Show this button by default -->
|
<!-- TODO : Bug 1165122 : Show this button by default -->
|
||||||
<button hidden="true" id="ruleview-add-rule-button" title="&addRuleButtonTooltip;" class="devtools-button"></button>
|
<button hidden="true" id="ruleview-add-rule-button" title="&addRuleButtonTooltip;" class="devtools-button"></button>
|
||||||
<button id="pseudo-class-panel-toggle" class="devtools-button"></button>
|
<button id="pseudo-class-panel-toggle" title="&togglePseudoClassPanel;" class="devtools-button"></button>
|
||||||
</div>
|
</div>
|
||||||
<div id="pseudo-class-panel" class="devtools-toolbar" hidden="true">
|
<div id="pseudo-class-panel" class="devtools-toolbar" hidden="true">
|
||||||
<label><input id="pseudo-hover-toggle" type="checkbox" value=":hover" />:hover</label>
|
<label><input id="pseudo-hover-toggle" type="checkbox" value=":hover" />:hover</label>
|
||||||
|
|
|
@ -63,6 +63,8 @@ function loadDocument(browser) {
|
||||||
function testNetmonitor(toolbox) {
|
function testNetmonitor(toolbox) {
|
||||||
let monitor = toolbox.getCurrentPanel();
|
let monitor = toolbox.getCurrentPanel();
|
||||||
let { RequestsMenu } = monitor.panelWin.NetMonitorView;
|
let { RequestsMenu } = monitor.panelWin.NetMonitorView;
|
||||||
|
RequestsMenu.lazyUpdate = false;
|
||||||
|
|
||||||
is(RequestsMenu.itemCount, 1, "Network request appears in the network panel");
|
is(RequestsMenu.itemCount, 1, "Network request appears in the network panel");
|
||||||
|
|
||||||
let item = RequestsMenu.getItemAtIndex(0);
|
let item = RequestsMenu.getItemAtIndex(0);
|
||||||
|
|
|
@ -63,6 +63,7 @@ function loadDocument(browser) {
|
||||||
function testNetmonitor(toolbox) {
|
function testNetmonitor(toolbox) {
|
||||||
let monitor = toolbox.getCurrentPanel();
|
let monitor = toolbox.getCurrentPanel();
|
||||||
let { RequestsMenu } = monitor.panelWin.NetMonitorView;
|
let { RequestsMenu } = monitor.panelWin.NetMonitorView;
|
||||||
|
RequestsMenu.lazyUpdate = false;
|
||||||
is(RequestsMenu.itemCount, 1, "Network request appears in the network panel");
|
is(RequestsMenu.itemCount, 1, "Network request appears in the network panel");
|
||||||
|
|
||||||
let item = RequestsMenu.getItemAtIndex(0);
|
let item = RequestsMenu.getItemAtIndex(0);
|
||||||
|
|
|
@ -489,6 +489,7 @@
|
||||||
@RESPATH@/browser/components/ChromeProfileMigrator.js
|
@RESPATH@/browser/components/ChromeProfileMigrator.js
|
||||||
@RESPATH@/browser/components/FirefoxProfileMigrator.js
|
@RESPATH@/browser/components/FirefoxProfileMigrator.js
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
|
@RESPATH@/browser/components/360seProfileMigrator.js
|
||||||
@RESPATH@/browser/components/IEProfileMigrator.js
|
@RESPATH@/browser/components/IEProfileMigrator.js
|
||||||
@RESPATH@/browser/components/SafariProfileMigrator.js
|
@RESPATH@/browser/components/SafariProfileMigrator.js
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -27,6 +27,11 @@
|
||||||
- tree. -->
|
- tree. -->
|
||||||
<!ENTITY selectedElementLabel "Selected element:">
|
<!ENTITY selectedElementLabel "Selected element:">
|
||||||
|
|
||||||
|
<!-- LOCALIZATION NOTE (togglePseudoClassPanel): This is the tooltip
|
||||||
|
- shown when hovering over the `Toggle Pseudo Class Panel` button in the
|
||||||
|
- rule view toolbar. -->
|
||||||
|
<!ENTITY togglePseudoClassPanel "Toggle pseudo-classes">
|
||||||
|
|
||||||
<!-- LOCALIZATION NOTE (noPropertiesFound): In the case where there are no CSS
|
<!-- LOCALIZATION NOTE (noPropertiesFound): In the case where there are no CSS
|
||||||
- properties to display e.g. due to search criteria this message is
|
- properties to display e.g. due to search criteria this message is
|
||||||
- displayed. -->
|
- displayed. -->
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
<!ENTITY toolboxZoomReset.key "0">
|
<!ENTITY toolboxZoomReset.key "0">
|
||||||
|
|
||||||
<!ENTITY toolboxReload.key "r">
|
<!ENTITY toolboxReload.key "r">
|
||||||
|
<!-- This key is used with the accel+shift modifiers to minimize the toolbox -->
|
||||||
|
<!ENTITY toolboxToggleMinimize.key "U">
|
||||||
|
|
||||||
<!-- LOCALIZATION NOTE (toolboxFramesButton): This is the label for
|
<!-- LOCALIZATION NOTE (toolboxFramesButton): This is the label for
|
||||||
- the iframes menu list that appears only when the document has some.
|
- the iframes menu list that appears only when the document has some.
|
||||||
- It allows you to switch the context of the whole toolbox. -->
|
- It allows you to switch the context of the whole toolbox. -->
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
<!ENTITY importFromChrome.accesskey "C">
|
<!ENTITY importFromChrome.accesskey "C">
|
||||||
<!ENTITY importFromFirefox.label "Firefox">
|
<!ENTITY importFromFirefox.label "Firefox">
|
||||||
<!ENTITY importFromFirefox.accesskey "X">
|
<!ENTITY importFromFirefox.accesskey "X">
|
||||||
|
<!ENTITY importFrom360se.label "360 Secure Browser">
|
||||||
|
<!ENTITY importFrom360se.accesskey "3">
|
||||||
|
|
||||||
<!ENTITY noMigrationSources.label "No programs that contain bookmarks, history or password data could be found.">
|
<!ENTITY noMigrationSources.label "No programs that contain bookmarks, history or password data could be found.">
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ sourceNameIE=Internet Explorer
|
||||||
sourceNameSafari=Safari
|
sourceNameSafari=Safari
|
||||||
sourceNameChrome=Google Chrome
|
sourceNameChrome=Google Chrome
|
||||||
sourceNameFirefox=Mozilla Firefox
|
sourceNameFirefox=Mozilla Firefox
|
||||||
|
sourceName360se=360 Secure Browser
|
||||||
|
|
||||||
importedBookmarksFolder=From %S
|
importedBookmarksFolder=From %S
|
||||||
|
|
||||||
|
@ -20,34 +21,41 @@ importedSafariReadingList=Reading List (From Safari)
|
||||||
1_ie=Internet Options
|
1_ie=Internet Options
|
||||||
1_safari=Preferences
|
1_safari=Preferences
|
||||||
1_chrome=Preferences
|
1_chrome=Preferences
|
||||||
|
1_360se=Preferences
|
||||||
|
|
||||||
2_ie=Cookies
|
2_ie=Cookies
|
||||||
2_safari=Cookies
|
2_safari=Cookies
|
||||||
2_chrome=Cookies
|
2_chrome=Cookies
|
||||||
2_firefox=Cookies
|
2_firefox=Cookies
|
||||||
|
2_360se=Cookies
|
||||||
|
|
||||||
4_ie=Browsing History
|
4_ie=Browsing History
|
||||||
4_safari=Browsing History
|
4_safari=Browsing History
|
||||||
4_chrome=Browsing History
|
4_chrome=Browsing History
|
||||||
4_firefox_history_and_bookmarks=Browsing History and Bookmarks
|
4_firefox_history_and_bookmarks=Browsing History and Bookmarks
|
||||||
|
4_360se=Browsing History
|
||||||
|
|
||||||
8_ie=Saved Form History
|
8_ie=Saved Form History
|
||||||
8_safari=Saved Form History
|
8_safari=Saved Form History
|
||||||
8_chrome=Saved Form History
|
8_chrome=Saved Form History
|
||||||
8_firefox=Saved Form History
|
8_firefox=Saved Form History
|
||||||
|
8_360se=Saved Form History
|
||||||
|
|
||||||
16_ie=Saved Passwords
|
16_ie=Saved Passwords
|
||||||
16_safari=Saved Passwords
|
16_safari=Saved Passwords
|
||||||
16_chrome=Saved Passwords
|
16_chrome=Saved Passwords
|
||||||
16_firefox=Saved Passwords
|
16_firefox=Saved Passwords
|
||||||
|
16_360se=Saved Passwords
|
||||||
|
|
||||||
32_ie=Favorites
|
32_ie=Favorites
|
||||||
32_safari=Bookmarks
|
32_safari=Bookmarks
|
||||||
32_chrome=Bookmarks
|
32_chrome=Bookmarks
|
||||||
|
32_360se=Bookmarks
|
||||||
|
|
||||||
64_ie=Other Data
|
64_ie=Other Data
|
||||||
64_safari=Other Data
|
64_safari=Other Data
|
||||||
64_chrome=Other Data
|
64_chrome=Other Data
|
||||||
64_firefox_other=Other Data
|
64_firefox_other=Other Data
|
||||||
|
64_360se=Other Data
|
||||||
|
|
||||||
128_firefox=Windows and Tabs
|
128_firefox=Windows and Tabs
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
<!ENTITY font.langGroup.gurmukhi "Gurmukhi">
|
<!ENTITY font.langGroup.gurmukhi "Gurmukhi">
|
||||||
<!ENTITY font.langGroup.khmer "Khmer">
|
<!ENTITY font.langGroup.khmer "Khmer">
|
||||||
<!ENTITY font.langGroup.malayalam "Malayalam">
|
<!ENTITY font.langGroup.malayalam "Malayalam">
|
||||||
|
<!ENTITY font.langGroup.math "Mathematics">
|
||||||
<!ENTITY font.langGroup.oriya "Oriya">
|
<!ENTITY font.langGroup.oriya "Oriya">
|
||||||
<!ENTITY font.langGroup.telugu "Telugu">
|
<!ENTITY font.langGroup.telugu "Telugu">
|
||||||
<!ENTITY font.langGroup.kannada "Kannada">
|
<!ENTITY font.langGroup.kannada "Kannada">
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
<!ENTITY locbar.bookmarks.accesskey "k">
|
<!ENTITY locbar.bookmarks.accesskey "k">
|
||||||
<!ENTITY locbar.openpage.label "Open tabs">
|
<!ENTITY locbar.openpage.label "Open tabs">
|
||||||
<!ENTITY locbar.openpage.accesskey "O">
|
<!ENTITY locbar.openpage.accesskey "O">
|
||||||
|
<!ENTITY locbar.searches.label "Related searches from the default search engine">
|
||||||
|
<!ENTITY locbar.searches.accesskey "d">
|
||||||
|
|
||||||
<!ENTITY acceptCookies.label "Accept cookies from sites">
|
<!ENTITY acceptCookies.label "Accept cookies from sites">
|
||||||
<!ENTITY acceptCookies.accesskey "A">
|
<!ENTITY acceptCookies.accesskey "A">
|
||||||
|
|
|
@ -121,6 +121,11 @@
|
||||||
margin-top: @windowButtonMarginTop@;
|
margin-top: @windowButtonMarginTop@;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#main-window:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-buttonbox-container:-moz-lwtheme,
|
||||||
|
#main-window:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > #titlebar-fullscreen-button:-moz-lwtheme {
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
#main-window[customize-entered] > #titlebar {
|
#main-window[customize-entered] > #titlebar {
|
||||||
-moz-appearance: none;
|
-moz-appearance: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,18 @@
|
||||||
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#bookmark-disabled");
|
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#bookmark-disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#context-bookmarkpage[starred=true] {
|
||||||
|
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#bookmarked");
|
||||||
|
}
|
||||||
|
|
||||||
|
#context-bookmarkpage[starred=true][_moz-menuactive=true] {
|
||||||
|
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#bookmarked-active");
|
||||||
|
}
|
||||||
|
|
||||||
|
#context-bookmarkpage[starred=true][disabled=true] {
|
||||||
|
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#bookmarked-disabled");
|
||||||
|
}
|
||||||
|
|
||||||
#context-back:-moz-locale-dir(rtl),
|
#context-back:-moz-locale-dir(rtl),
|
||||||
#context-forward:-moz-locale-dir(rtl),
|
#context-forward:-moz-locale-dir(rtl),
|
||||||
#context-reload:-moz-locale-dir(rtl) {
|
#context-reload:-moz-locale-dir(rtl) {
|
||||||
|
|
|
@ -384,7 +384,8 @@ static const char kPermissionChangeNotification[] = PERM_CHANGE_NOTIFICATION;
|
||||||
NS_IMPL_ISUPPORTS(nsPermissionManager, nsIPermissionManager, nsIObserver, nsISupportsWeakReference)
|
NS_IMPL_ISUPPORTS(nsPermissionManager, nsIPermissionManager, nsIObserver, nsISupportsWeakReference)
|
||||||
|
|
||||||
nsPermissionManager::nsPermissionManager()
|
nsPermissionManager::nsPermissionManager()
|
||||||
: mLargestID(0)
|
: mMemoryOnlyDB(false)
|
||||||
|
, mLargestID(0)
|
||||||
, mIsShuttingDown(false)
|
, mIsShuttingDown(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -426,6 +427,10 @@ nsPermissionManager::Init()
|
||||||
{
|
{
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
|
||||||
|
// If the 'permissions.memory_only' pref is set to true, then don't write any
|
||||||
|
// permission settings to disk, but keep them in a memory-only database.
|
||||||
|
mMemoryOnlyDB = mozilla::Preferences::GetBool("permissions.memory_only", false);
|
||||||
|
|
||||||
mObserverService = do_GetService("@mozilla.org/observer-service;1", &rv);
|
mObserverService = do_GetService("@mozilla.org/observer-service;1", &rv);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
mObserverService->AddObserver(this, "profile-before-change", true);
|
mObserverService->AddObserver(this, "profile-before-change", true);
|
||||||
|
@ -457,6 +462,23 @@ nsPermissionManager::RefreshPermission() {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsPermissionManager::OpenDatabase(nsIFile* aPermissionsFile)
|
||||||
|
{
|
||||||
|
nsresult rv;
|
||||||
|
nsCOMPtr<mozIStorageService> storage = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
|
||||||
|
if (!storage) {
|
||||||
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
// cache a connection to the hosts database
|
||||||
|
if (mMemoryOnlyDB) {
|
||||||
|
rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn));
|
||||||
|
} else {
|
||||||
|
rv = storage->OpenDatabase(aPermissionsFile, getter_AddRefs(mDBConn));
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsPermissionManager::InitDB(bool aRemoveFile)
|
nsPermissionManager::InitDB(bool aRemoveFile)
|
||||||
{
|
{
|
||||||
|
@ -480,13 +502,10 @@ nsPermissionManager::InitDB(bool aRemoveFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<mozIStorageService> storage = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
|
rv = OpenDatabase(permissionsFile);
|
||||||
if (!storage)
|
if (rv == NS_ERROR_UNEXPECTED) {
|
||||||
return NS_ERROR_UNEXPECTED;
|
return rv;
|
||||||
|
} else if (rv == NS_ERROR_FILE_CORRUPTED) {
|
||||||
// cache a connection to the hosts database
|
|
||||||
rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
|
|
||||||
if (rv == NS_ERROR_FILE_CORRUPTED) {
|
|
||||||
LogToConsole(NS_LITERAL_STRING("permissions.sqlite is corrupted! Try again!"));
|
LogToConsole(NS_LITERAL_STRING("permissions.sqlite is corrupted! Try again!"));
|
||||||
|
|
||||||
// Add telemetry probe
|
// Add telemetry probe
|
||||||
|
@ -497,7 +516,7 @@ nsPermissionManager::InitDB(bool aRemoveFile)
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
LogToConsole(NS_LITERAL_STRING("Corrupted permissions.sqlite has been removed."));
|
LogToConsole(NS_LITERAL_STRING("Corrupted permissions.sqlite has been removed."));
|
||||||
|
|
||||||
rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
|
rv = OpenDatabase(permissionsFile);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
LogToConsole(NS_LITERAL_STRING("OpenDatabase to permissions.sqlite is successful!"));
|
LogToConsole(NS_LITERAL_STRING("OpenDatabase to permissions.sqlite is successful!"));
|
||||||
}
|
}
|
||||||
|
@ -515,7 +534,7 @@ nsPermissionManager::InitDB(bool aRemoveFile)
|
||||||
// Add telemetry probe
|
// Add telemetry probe
|
||||||
mozilla::Telemetry::Accumulate(mozilla::Telemetry::DEFECTIVE_PERMISSIONS_SQL_REMOVED, 1);
|
mozilla::Telemetry::Accumulate(mozilla::Telemetry::DEFECTIVE_PERMISSIONS_SQL_REMOVED, 1);
|
||||||
|
|
||||||
rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
|
rv = OpenDatabase(permissionsFile);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
LogToConsole(NS_LITERAL_STRING("OpenDatabase to permissions.sqlite is successful!"));
|
LogToConsole(NS_LITERAL_STRING("OpenDatabase to permissions.sqlite is successful!"));
|
||||||
|
|
||||||
|
|
|
@ -234,6 +234,7 @@ private:
|
||||||
bool aExactHostMatch,
|
bool aExactHostMatch,
|
||||||
bool aIncludingSession);
|
bool aIncludingSession);
|
||||||
|
|
||||||
|
nsresult OpenDatabase(nsIFile* permissionsFile);
|
||||||
nsresult InitDB(bool aRemoveFile);
|
nsresult InitDB(bool aRemoveFile);
|
||||||
nsresult CreateTable();
|
nsresult CreateTable();
|
||||||
nsresult Import();
|
nsresult Import();
|
||||||
|
@ -326,6 +327,8 @@ private:
|
||||||
nsCOMPtr<mozIStorageAsyncStatement> mStmtDelete;
|
nsCOMPtr<mozIStorageAsyncStatement> mStmtDelete;
|
||||||
nsCOMPtr<mozIStorageAsyncStatement> mStmtUpdate;
|
nsCOMPtr<mozIStorageAsyncStatement> mStmtUpdate;
|
||||||
|
|
||||||
|
bool mMemoryOnlyDB;
|
||||||
|
|
||||||
nsTHashtable<PermissionHashKey> mPermissionTable;
|
nsTHashtable<PermissionHashKey> mPermissionTable;
|
||||||
// a unique, monotonically increasing id used to identify each database entry
|
// a unique, monotonically increasing id used to identify each database entry
|
||||||
int64_t mLargestID;
|
int64_t mLargestID;
|
||||||
|
|
|
@ -221,6 +221,9 @@ class RefTest(object):
|
||||||
# And for about:newtab content fetch and pings.
|
# And for about:newtab content fetch and pings.
|
||||||
prefs['browser.newtabpage.directory.source'] = 'data:application/json,{"reftest":1}'
|
prefs['browser.newtabpage.directory.source'] = 'data:application/json,{"reftest":1}'
|
||||||
prefs['browser.newtabpage.directory.ping'] = ''
|
prefs['browser.newtabpage.directory.ping'] = ''
|
||||||
|
# Only allow add-ons from the profile and app and allow foreign injection
|
||||||
|
prefs["extensions.enabledScopes"] = 5;
|
||||||
|
prefs["extensions.autoDisableScopes"] = 0;
|
||||||
# Allow unsigned add-ons
|
# Allow unsigned add-ons
|
||||||
prefs['xpinstall.signatures.required'] = False
|
prefs['xpinstall.signatures.required'] = False
|
||||||
|
|
||||||
|
|
|
@ -1773,7 +1773,7 @@ public class GeckoAppShell
|
||||||
String[] split = output.split("\\s+");
|
String[] split = output.split("\\s+");
|
||||||
if (split.length <= pidColumn || split.length <= nameColumn)
|
if (split.length <= pidColumn || split.length <= nameColumn)
|
||||||
continue;
|
continue;
|
||||||
Integer pid = new Integer(split[pidColumn]);
|
final Integer pid = Integer.valueOf(split[pidColumn]);
|
||||||
String name = pidNameMap.get(pid);
|
String name = pidNameMap.get(pid);
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
name = getAppNameByPID(pid.intValue());
|
name = getAppNameByPID(pid.intValue());
|
||||||
|
|
|
@ -5,11 +5,13 @@
|
||||||
|
|
||||||
package org.mozilla.gecko;
|
package org.mozilla.gecko;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
public class SiteIdentity {
|
public class SiteIdentity {
|
||||||
|
private final String LOGTAG = "GeckoSiteIdentity";
|
||||||
private SecurityMode mSecurityMode;
|
private SecurityMode mSecurityMode;
|
||||||
private MixedMode mMixedMode;
|
private MixedMode mMixedMode;
|
||||||
private TrackingMode mTrackingMode;
|
private TrackingMode mTrackingMode;
|
||||||
|
@ -17,7 +19,8 @@ public class SiteIdentity {
|
||||||
private String mOwner;
|
private String mOwner;
|
||||||
private String mSupplemental;
|
private String mSupplemental;
|
||||||
private String mVerifier;
|
private String mVerifier;
|
||||||
private String mEncrypted;
|
private boolean mEncrypted;
|
||||||
|
private String mOrigin;
|
||||||
|
|
||||||
// The order of the items here relate to image levels in
|
// The order of the items here relate to image levels in
|
||||||
// site_security_level.xml
|
// site_security_level.xml
|
||||||
|
@ -124,11 +127,12 @@ public class SiteIdentity {
|
||||||
|
|
||||||
public void resetIdentity() {
|
public void resetIdentity() {
|
||||||
mSecurityMode = SecurityMode.UNKNOWN;
|
mSecurityMode = SecurityMode.UNKNOWN;
|
||||||
|
mOrigin = null;
|
||||||
mHost = null;
|
mHost = null;
|
||||||
mOwner = null;
|
mOwner = null;
|
||||||
mSupplemental = null;
|
mSupplemental = null;
|
||||||
mVerifier = null;
|
mVerifier = null;
|
||||||
mEncrypted = null;
|
mEncrypted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
|
@ -166,12 +170,14 @@ public class SiteIdentity {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
mOrigin = identityData.getString("origin");
|
||||||
mHost = identityData.getString("host");
|
mHost = identityData.getString("host");
|
||||||
mOwner = identityData.optString("owner", null);
|
mOwner = identityData.optString("owner", null);
|
||||||
mSupplemental = identityData.optString("supplemental", null);
|
mSupplemental = identityData.optString("supplemental", null);
|
||||||
mVerifier = identityData.getString("verifier");
|
mVerifier = identityData.getString("verifier");
|
||||||
mEncrypted = identityData.getString("encrypted");
|
mEncrypted = identityData.optBoolean("encrypted", false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
Log.e(LOGTAG, "Error fetching Site identity host info", e);
|
||||||
resetIdentity();
|
resetIdentity();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -183,6 +189,10 @@ public class SiteIdentity {
|
||||||
return mSecurityMode;
|
return mSecurityMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getOrigin() {
|
||||||
|
return mOrigin;
|
||||||
|
}
|
||||||
|
|
||||||
public String getHost() {
|
public String getHost() {
|
||||||
return mHost;
|
return mHost;
|
||||||
}
|
}
|
||||||
|
@ -199,7 +209,7 @@ public class SiteIdentity {
|
||||||
return mVerifier;
|
return mVerifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEncrypted() {
|
public boolean getEncrypted() {
|
||||||
return mEncrypted;
|
return mEncrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -452,7 +452,6 @@ size. -->
|
||||||
<!ENTITY button_clear_data "Clear data">
|
<!ENTITY button_clear_data "Clear data">
|
||||||
<!ENTITY button_set "Set">
|
<!ENTITY button_set "Set">
|
||||||
<!ENTITY button_clear "Clear">
|
<!ENTITY button_clear "Clear">
|
||||||
<!ENTITY button_remember "Remember">
|
|
||||||
<!ENTITY button_copy "Copy">
|
<!ENTITY button_copy "Copy">
|
||||||
|
|
||||||
<!ENTITY firstrun_panel_title_welcome "Welcome">
|
<!ENTITY firstrun_panel_title_welcome "Welcome">
|
||||||
|
@ -548,6 +547,7 @@ just addresses the organization to follow, e.g. "This site is run by " -->
|
||||||
<!ENTITY identity_run_by "which is run by">
|
<!ENTITY identity_run_by "which is run by">
|
||||||
<!ENTITY identity_no_info "This website does not supply identity information.">
|
<!ENTITY identity_no_info "This website does not supply identity information.">
|
||||||
<!ENTITY identity_not_encrypted "Your connection to this website is not encrypted.">
|
<!ENTITY identity_not_encrypted "Your connection to this website is not encrypted.">
|
||||||
|
<!ENTITY identity_encrypted "Encrypted">
|
||||||
|
|
||||||
<!-- Mixed content notifications in site identity popup -->
|
<!-- Mixed content notifications in site identity popup -->
|
||||||
<!ENTITY loaded_mixed_content_message "This page is displaying content that isn\'t secure.">
|
<!ENTITY loaded_mixed_content_message "This page is displaying content that isn\'t secure.">
|
||||||
|
|
До Ширина: | Высота: | Размер: 1.7 KiB |
До Ширина: | Высота: | Размер: 1.6 KiB |
До Ширина: | Высота: | Размер: 1.2 KiB |
До Ширина: | Высота: | Размер: 1.6 KiB |
До Ширина: | Высота: | Размер: 1.1 KiB |
До Ширина: | Высота: | Размер: 1.1 KiB |
До Ширина: | Высота: | Размер: 899 B |
До Ширина: | Высота: | Размер: 1.2 KiB |
До Ширина: | Высота: | Размер: 2.1 KiB |
До Ширина: | Высота: | Размер: 2.0 KiB |
До Ширина: | Высота: | Размер: 1.5 KiB |
До Ширина: | Высота: | Размер: 2.0 KiB |
До Ширина: | Высота: | Размер: 3.0 KiB |
До Ширина: | Высота: | Размер: 2.9 KiB |
До Ширина: | Высота: | Размер: 2.3 KiB |
До Ширина: | Высота: | Размер: 3.2 KiB |
|
@ -14,8 +14,8 @@
|
||||||
android:padding="@dimen/doorhanger_padding">
|
android:padding="@dimen/doorhanger_padding">
|
||||||
|
|
||||||
<ImageView android:id="@+id/larry"
|
<ImageView android:id="@+id/larry"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="@dimen/doorhanger_icon_size"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="@dimen/doorhanger_icon_size"
|
||||||
android:src="@drawable/larry"
|
android:src="@drawable/larry"
|
||||||
android:paddingRight="@dimen/doorhanger_padding"/>
|
android:paddingRight="@dimen/doorhanger_padding"/>
|
||||||
|
|
||||||
|
@ -32,6 +32,20 @@
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView android:id="@+id/site_identity_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="@dimen/doorhanger_section_padding_small"
|
||||||
|
android:textAppearance="@style/TextAppearance.DoorHanger.Medium.Light"/>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/site_identity_encrypted"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="@dimen/doorhanger_section_padding_small"
|
||||||
|
android:textAppearance="@style/TextAppearance.DoorHanger.Medium.Bold"
|
||||||
|
android:textColor="@color/affirmative_green"
|
||||||
|
android:text="@string/identity_encrypted"/>
|
||||||
|
|
||||||
<TextView android:layout_width="wrap_content"
|
<TextView android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="@style/TextAppearance.DoorHanger.Medium.Light"
|
android:textAppearance="@style/TextAppearance.DoorHanger.Medium.Light"
|
||||||
|
@ -70,7 +84,8 @@
|
||||||
android:textColor="@color/link_blue"
|
android:textColor="@color/link_blue"
|
||||||
android:layout_marginTop="@dimen/doorhanger_section_padding_large"
|
android:layout_marginTop="@dimen/doorhanger_section_padding_large"
|
||||||
android:layout_marginBottom="@dimen/doorhanger_padding"
|
android:layout_marginBottom="@dimen/doorhanger_padding"
|
||||||
android:text="@string/contextmenu_site_settings"/>
|
android:text="@string/contextmenu_site_settings"
|
||||||
|
android:visibility="gone"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
<resources>
|
<resources>
|
||||||
<!-- Fennec color palette (bug 1127517) -->
|
<!-- Fennec color palette (bug 1127517) -->
|
||||||
<color name="fennec_ui_orange">#FF9500</color>
|
<color name="fennec_ui_orange">#FF9500</color>
|
||||||
|
<color name="affirmative_green">#6FBE4A</color>
|
||||||
<color name="action_orange">#E66000</color>
|
<color name="action_orange">#E66000</color>
|
||||||
<color name="action_orange_pressed">#DC5600</color>
|
<color name="action_orange_pressed">#DC5600</color>
|
||||||
<color name="link_blue">#0096DD</color>
|
<color name="link_blue">#0096DD</color>
|
||||||
|
|
|
@ -427,6 +427,10 @@
|
||||||
<item name="android:textSize">16dp</item>
|
<item name="android:textSize">16dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="TextAppearance.DoorHanger.Medium.Bold">
|
||||||
|
<item name="android:fontFamily">sans-serif-medium</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="TextAppearance.DoorHanger.Medium.Light">
|
<style name="TextAppearance.DoorHanger.Medium.Light">
|
||||||
<item name="android:fontFamily">sans-serif-light</item>
|
<item name="android:fontFamily">sans-serif-light</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -385,7 +385,6 @@
|
||||||
<string name="button_clear">&button_clear;</string>
|
<string name="button_clear">&button_clear;</string>
|
||||||
<string name="button_yes">&button_yes;</string>
|
<string name="button_yes">&button_yes;</string>
|
||||||
<string name="button_no">&button_no;</string>
|
<string name="button_no">&button_no;</string>
|
||||||
<string name="button_remember">&button_remember;</string>
|
|
||||||
<string name="button_copy">&button_copy;</string>
|
<string name="button_copy">&button_copy;</string>
|
||||||
|
|
||||||
<string name="firstrun_panel_title_welcome">&firstrun_panel_title_welcome;</string>
|
<string name="firstrun_panel_title_welcome">&firstrun_panel_title_welcome;</string>
|
||||||
|
@ -458,6 +457,7 @@
|
||||||
<string name="identity_run_by">&identity_run_by;</string>
|
<string name="identity_run_by">&identity_run_by;</string>
|
||||||
<string name="identity_no_info">&identity_no_info;</string>
|
<string name="identity_no_info">&identity_no_info;</string>
|
||||||
<string name="identity_not_encrypted">&identity_not_encrypted;</string>
|
<string name="identity_not_encrypted">&identity_not_encrypted;</string>
|
||||||
|
<string name="identity_encrypted">&identity_encrypted;</string>
|
||||||
<string name="loaded_mixed_content_message">&loaded_mixed_content_message;</string>
|
<string name="loaded_mixed_content_message">&loaded_mixed_content_message;</string>
|
||||||
<string name="blocked_mixed_content_message_top">&blocked_mixed_content_message_top;</string>
|
<string name="blocked_mixed_content_message_top">&blocked_mixed_content_message_top;</string>
|
||||||
<string name="blocked_mixed_content_message_bottom">&blocked_mixed_content_message_bottom;</string>
|
<string name="blocked_mixed_content_message_bottom">&blocked_mixed_content_message_bottom;</string>
|
||||||
|
|
|
@ -102,8 +102,8 @@ public class AccountPickler {
|
||||||
final SyncAccountParameters params, final boolean syncAutomatically) {
|
final SyncAccountParameters params, final boolean syncAutomatically) {
|
||||||
final ExtendedJSONObject o = params.asJSON();
|
final ExtendedJSONObject o = params.asJSON();
|
||||||
o.put(Constants.JSON_KEY_SYNC_AUTOMATICALLY, Boolean.valueOf(syncAutomatically));
|
o.put(Constants.JSON_KEY_SYNC_AUTOMATICALLY, Boolean.valueOf(syncAutomatically));
|
||||||
o.put(Constants.JSON_KEY_VERSION, new Long(VERSION));
|
o.put(Constants.JSON_KEY_VERSION, Long.valueOf(VERSION));
|
||||||
o.put(Constants.JSON_KEY_TIMESTAMP, new Long(System.currentTimeMillis()));
|
o.put(Constants.JSON_KEY_TIMESTAMP, Long.valueOf(System.currentTimeMillis()));
|
||||||
|
|
||||||
PrintStream ps = null;
|
PrintStream ps = null;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -6,6 +6,8 @@ package org.mozilla.gecko.toolbar;
|
||||||
|
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
|
@ -21,6 +23,8 @@ import org.mozilla.gecko.SiteIdentity.MixedMode;
|
||||||
import org.mozilla.gecko.SiteIdentity.TrackingMode;
|
import org.mozilla.gecko.SiteIdentity.TrackingMode;
|
||||||
import org.mozilla.gecko.Tab;
|
import org.mozilla.gecko.Tab;
|
||||||
import org.mozilla.gecko.Tabs;
|
import org.mozilla.gecko.Tabs;
|
||||||
|
import org.mozilla.gecko.favicons.Favicons;
|
||||||
|
import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
|
||||||
import org.mozilla.gecko.util.GeckoEventListener;
|
import org.mozilla.gecko.util.GeckoEventListener;
|
||||||
import org.mozilla.gecko.util.ThreadUtils;
|
import org.mozilla.gecko.util.ThreadUtils;
|
||||||
import org.mozilla.gecko.widget.AnchoredPopup;
|
import org.mozilla.gecko.widget.AnchoredPopup;
|
||||||
|
@ -64,10 +68,13 @@ public class SiteIdentityPopup extends AnchoredPopup implements GeckoEventListen
|
||||||
private LinearLayout mIdentityKnownContainer;
|
private LinearLayout mIdentityKnownContainer;
|
||||||
private LinearLayout mIdentityUnknownContainer;
|
private LinearLayout mIdentityUnknownContainer;
|
||||||
|
|
||||||
|
private TextView mTitle;
|
||||||
|
private TextView mEncrypted;
|
||||||
private TextView mHost;
|
private TextView mHost;
|
||||||
private TextView mOwnerLabel;
|
private TextView mOwnerLabel;
|
||||||
private TextView mOwner;
|
private TextView mOwner;
|
||||||
private TextView mVerifier;
|
private TextView mVerifier;
|
||||||
|
private TextView mSiteSettingsLink;
|
||||||
|
|
||||||
private View mDivider;
|
private View mDivider;
|
||||||
|
|
||||||
|
@ -82,6 +89,7 @@ public class SiteIdentityPopup extends AnchoredPopup implements GeckoEventListen
|
||||||
|
|
||||||
mContentButtonClickListener = new ContentNotificationButtonListener();
|
mContentButtonClickListener = new ContentNotificationButtonListener();
|
||||||
EventDispatcher.getInstance().registerGeckoThreadListener(this, "Doorhanger:Logins");
|
EventDispatcher.getInstance().registerGeckoThreadListener(this, "Doorhanger:Logins");
|
||||||
|
EventDispatcher.getInstance().registerGeckoThreadListener(this, "Permissions:CheckResult");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -101,20 +109,16 @@ public class SiteIdentityPopup extends AnchoredPopup implements GeckoEventListen
|
||||||
mIdentityUnknownContainer =
|
mIdentityUnknownContainer =
|
||||||
(LinearLayout) mIdentity.findViewById(R.id.site_identity_unknown_container);
|
(LinearLayout) mIdentity.findViewById(R.id.site_identity_unknown_container);
|
||||||
|
|
||||||
|
|
||||||
|
mTitle = (TextView) mIdentityKnownContainer.findViewById(R.id.site_identity_title);
|
||||||
|
mEncrypted = (TextView) mIdentityKnownContainer.findViewById(R.id.site_identity_encrypted);
|
||||||
mHost = (TextView) mIdentityKnownContainer.findViewById(R.id.host);
|
mHost = (TextView) mIdentityKnownContainer.findViewById(R.id.host);
|
||||||
mOwnerLabel = (TextView) mIdentityKnownContainer.findViewById(R.id.owner_label);
|
mOwnerLabel = (TextView) mIdentityKnownContainer.findViewById(R.id.owner_label);
|
||||||
mOwner = (TextView) mIdentityKnownContainer.findViewById(R.id.owner);
|
mOwner = (TextView) mIdentityKnownContainer.findViewById(R.id.owner);
|
||||||
mVerifier = (TextView) mIdentityKnownContainer.findViewById(R.id.verifier);
|
mVerifier = (TextView) mIdentityKnownContainer.findViewById(R.id.verifier);
|
||||||
mDivider = mIdentity.findViewById(R.id.divider_doorhanger);
|
mDivider = mIdentity.findViewById(R.id.divider_doorhanger);
|
||||||
|
|
||||||
final TextView siteSettingsLink = (TextView) mIdentity.findViewById(R.id.site_settings_link);
|
mSiteSettingsLink = (TextView) mIdentity.findViewById(R.id.site_settings_link);
|
||||||
siteSettingsLink.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Permissions:Get", null));
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateIdentity(final SiteIdentity siteIdentity) {
|
private void updateIdentity(final SiteIdentity siteIdentity) {
|
||||||
|
@ -128,6 +132,9 @@ public class SiteIdentityPopup extends AnchoredPopup implements GeckoEventListen
|
||||||
if (isIdentityKnown) {
|
if (isIdentityKnown) {
|
||||||
updateIdentityInformation(siteIdentity);
|
updateIdentityInformation(siteIdentity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(
|
||||||
|
"Permissions:Check", null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -145,6 +152,24 @@ public class SiteIdentityPopup extends AnchoredPopup implements GeckoEventListen
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
Log.e(LOGTAG, "Error accessing logins in Doorhanger:Logins message", e);
|
Log.e(LOGTAG, "Error accessing logins in Doorhanger:Logins message", e);
|
||||||
}
|
}
|
||||||
|
} else if ("Permissions:CheckResult".equals(event)) {
|
||||||
|
final boolean hasPermissions = geckoObject.optBoolean("hasPermissions", false);
|
||||||
|
if (hasPermissions) {
|
||||||
|
mSiteSettingsLink.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Permissions:Get", null));
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadUtils.postToUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
mSiteSettingsLink.setVisibility(hasPermissions ? View.VISIBLE : View.GONE);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,6 +293,25 @@ public class SiteIdentityPopup extends AnchoredPopup implements GeckoEventListen
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateIdentityInformation(final SiteIdentity siteIdentity) {
|
private void updateIdentityInformation(final SiteIdentity siteIdentity) {
|
||||||
|
final String host = siteIdentity.getHost();
|
||||||
|
mTitle.setText(host);
|
||||||
|
|
||||||
|
final String hostUrl = siteIdentity.getOrigin();
|
||||||
|
Favicons.getSizedFaviconForPageFromLocal(mContext, hostUrl, 32, new OnFaviconLoadedListener() {
|
||||||
|
@Override
|
||||||
|
public void onFaviconLoaded(String url, String faviconURL, Bitmap favicon) {
|
||||||
|
if (favicon == null) {
|
||||||
|
// If there is no favicon, clear the compound drawable.
|
||||||
|
mTitle.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
|
||||||
|
} else {
|
||||||
|
mTitle.setCompoundDrawablesWithIntrinsicBounds(new BitmapDrawable(mContext.getResources(), favicon), null, null, null);
|
||||||
|
mTitle.setCompoundDrawablePadding((int) mContext.getResources().getDimension(R.dimen.doorhanger_drawable_padding));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mEncrypted.setVisibility(siteIdentity.getEncrypted() ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
mHost.setText(siteIdentity.getHost());
|
mHost.setText(siteIdentity.getHost());
|
||||||
|
|
||||||
String owner = siteIdentity.getOwner();
|
String owner = siteIdentity.getOwner();
|
||||||
|
@ -287,8 +331,7 @@ public class SiteIdentityPopup extends AnchoredPopup implements GeckoEventListen
|
||||||
}
|
}
|
||||||
|
|
||||||
final String verifier = siteIdentity.getVerifier();
|
final String verifier = siteIdentity.getVerifier();
|
||||||
final String encrypted = siteIdentity.getEncrypted();
|
mVerifier.setText(verifier);
|
||||||
mVerifier.setText(verifier + "\n" + encrypted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMixedContentNotification(boolean blocked) {
|
private void addMixedContentNotification(boolean blocked) {
|
||||||
|
@ -439,6 +482,7 @@ public class SiteIdentityPopup extends AnchoredPopup implements GeckoEventListen
|
||||||
|
|
||||||
void destroy() {
|
void destroy() {
|
||||||
EventDispatcher.getInstance().unregisterGeckoThreadListener(this, "Doorhanger:Logins");
|
EventDispatcher.getInstance().unregisterGeckoThreadListener(this, "Doorhanger:Logins");
|
||||||
|
EventDispatcher.getInstance().unregisterGeckoThreadListener(this, "Permissions:CheckResult");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -38,7 +38,7 @@ public class LoginDoorHanger extends DoorHanger {
|
||||||
private final TextView mTitle;
|
private final TextView mTitle;
|
||||||
private final TextView mMessage;
|
private final TextView mMessage;
|
||||||
private final TextView mLink;
|
private final TextView mLink;
|
||||||
private int mCallbackID;
|
private final DoorhangerConfig.ButtonConfig mButtonConfig;
|
||||||
|
|
||||||
public LoginDoorHanger(Context context, DoorhangerConfig config) {
|
public LoginDoorHanger(Context context, DoorhangerConfig config) {
|
||||||
super(context, config, Type.LOGIN);
|
super(context, config, Type.LOGIN);
|
||||||
|
@ -49,6 +49,8 @@ public class LoginDoorHanger extends DoorHanger {
|
||||||
mIcon.setImageResource(R.drawable.icon_key);
|
mIcon.setImageResource(R.drawable.icon_key);
|
||||||
mIcon.setVisibility(View.VISIBLE);
|
mIcon.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
mButtonConfig = config.getPositiveButtonConfig();
|
||||||
|
|
||||||
loadConfig(config);
|
loadConfig(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +64,6 @@ public class LoginDoorHanger extends DoorHanger {
|
||||||
setOptions(config.getOptions());
|
setOptions(config.getOptions());
|
||||||
setMessage(config.getMessage());
|
setMessage(config.getMessage());
|
||||||
// Store the positive callback id for nested dialogs that need the same callback id.
|
// Store the positive callback id for nested dialogs that need the same callback id.
|
||||||
mCallbackID = config.getPositiveButtonConfig().callback;
|
|
||||||
addButtonsToLayout(config);
|
addButtonsToLayout(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,12 +161,12 @@ public class LoginDoorHanger extends DoorHanger {
|
||||||
});
|
});
|
||||||
builder.setView(view);
|
builder.setView(view);
|
||||||
|
|
||||||
builder.setPositiveButton(R.string.button_remember, new DialogInterface.OnClickListener() {
|
builder.setPositiveButton(mButtonConfig.label, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
JSONObject response = new JSONObject();
|
JSONObject response = new JSONObject();
|
||||||
try {
|
try {
|
||||||
response.put("callback", mCallbackID);
|
response.put("callback", mButtonConfig.callback);
|
||||||
final JSONObject inputs = new JSONObject();
|
final JSONObject inputs = new JSONObject();
|
||||||
inputs.put("username", username.getText());
|
inputs.put("username", username.getText());
|
||||||
inputs.put("password", password.getText());
|
inputs.put("password", password.getText());
|
||||||
|
@ -214,7 +215,7 @@ public class LoginDoorHanger extends DoorHanger {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
final JSONObject response = new JSONObject();
|
final JSONObject response = new JSONObject();
|
||||||
try {
|
try {
|
||||||
response.put("callback", mCallbackID);
|
response.put("callback", mButtonConfig.callback);
|
||||||
response.put("password", passwords[which]);
|
response.put("password", passwords[which]);
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
Log.e(LOGTAG, "Error making login select dialog JSON", e);
|
Log.e(LOGTAG, "Error making login select dialog JSON", e);
|
||||||
|
|
|
@ -51,8 +51,11 @@ var PermissionsHelper = {
|
||||||
|
|
||||||
observe: function observe(aSubject, aTopic, aData) {
|
observe: function observe(aSubject, aTopic, aData) {
|
||||||
let uri = BrowserApp.selectedBrowser.currentURI;
|
let uri = BrowserApp.selectedBrowser.currentURI;
|
||||||
|
let check = false;
|
||||||
|
|
||||||
switch (aTopic) {
|
switch (aTopic) {
|
||||||
|
case "Permissions:Check":
|
||||||
|
check = true;
|
||||||
case "Permissions:Get":
|
case "Permissions:Get":
|
||||||
let permissions = [];
|
let permissions = [];
|
||||||
for (let i = 0; i < this._permissonTypes.length; i++) {
|
for (let i = 0; i < this._permissonTypes.length; i++) {
|
||||||
|
@ -63,6 +66,13 @@ var PermissionsHelper = {
|
||||||
if (value == Services.perms.UNKNOWN_ACTION)
|
if (value == Services.perms.UNKNOWN_ACTION)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (check) {
|
||||||
|
Messaging.sendRequest({
|
||||||
|
type: "Permissions:CheckResult",
|
||||||
|
hasPermissions: true
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Get the strings that correspond to the permission type
|
// Get the strings that correspond to the permission type
|
||||||
let typeStrings = this._permissionStrings[type];
|
let typeStrings = this._permissionStrings[type];
|
||||||
let label = Strings.browser.GetStringFromName(typeStrings["label"]);
|
let label = Strings.browser.GetStringFromName(typeStrings["label"]);
|
||||||
|
@ -79,6 +89,14 @@ var PermissionsHelper = {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (check) {
|
||||||
|
Messaging.sendRequest({
|
||||||
|
type: "Permissions:CheckResult",
|
||||||
|
hasPermissions: false
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Keep track of permissions, so we know which ones to clear
|
// Keep track of permissions, so we know which ones to clear
|
||||||
this._currentPermissions = permissions;
|
this._currentPermissions = permissions;
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,7 @@ let lazilyLoadedObserverScripts = [
|
||||||
["MemoryObserver", ["memory-pressure", "Memory:Dump"], "chrome://browser/content/MemoryObserver.js"],
|
["MemoryObserver", ["memory-pressure", "Memory:Dump"], "chrome://browser/content/MemoryObserver.js"],
|
||||||
["ConsoleAPI", ["console-api-log-event"], "chrome://browser/content/ConsoleAPI.js"],
|
["ConsoleAPI", ["console-api-log-event"], "chrome://browser/content/ConsoleAPI.js"],
|
||||||
["FindHelper", ["FindInPage:Opened", "FindInPage:Closed", "Tab:Selected"], "chrome://browser/content/FindHelper.js"],
|
["FindHelper", ["FindInPage:Opened", "FindInPage:Closed", "Tab:Selected"], "chrome://browser/content/FindHelper.js"],
|
||||||
["PermissionsHelper", ["Permissions:Get", "Permissions:Clear"], "chrome://browser/content/PermissionsHelper.js"],
|
["PermissionsHelper", ["Permissions:Check", "Permissions:Get", "Permissions:Clear"], "chrome://browser/content/PermissionsHelper.js"],
|
||||||
["FeedHandler", ["Feeds:Subscribe"], "chrome://browser/content/FeedHandler.js"],
|
["FeedHandler", ["Feeds:Subscribe"], "chrome://browser/content/FeedHandler.js"],
|
||||||
["Feedback", ["Feedback:Show"], "chrome://browser/content/Feedback.js"],
|
["Feedback", ["Feedback:Show"], "chrome://browser/content/Feedback.js"],
|
||||||
["SelectionHandler", ["TextSelection:Get"], "chrome://browser/content/SelectionHandler.js"],
|
["SelectionHandler", ["TextSelection:Get"], "chrome://browser/content/SelectionHandler.js"],
|
||||||
|
@ -7028,6 +7028,7 @@ var IdentityHandler = {
|
||||||
locationObj.host = location.host;
|
locationObj.host = location.host;
|
||||||
locationObj.hostname = location.hostname;
|
locationObj.hostname = location.hostname;
|
||||||
locationObj.port = location.port;
|
locationObj.port = location.port;
|
||||||
|
locationObj.origin = location.origin;
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
// Can sometimes throw if the URL being visited has no host/hostname,
|
// Can sometimes throw if the URL being visited has no host/hostname,
|
||||||
// e.g. about:blank. The _state for these pages means we won't need these
|
// e.g. about:blank. The _state for these pages means we won't need these
|
||||||
|
@ -7039,6 +7040,7 @@ var IdentityHandler = {
|
||||||
let mixedMode = this.getMixedMode(aState);
|
let mixedMode = this.getMixedMode(aState);
|
||||||
let trackingMode = this.getTrackingMode(aState);
|
let trackingMode = this.getTrackingMode(aState);
|
||||||
let result = {
|
let result = {
|
||||||
|
origin: locationObj.origin,
|
||||||
mode: {
|
mode: {
|
||||||
identity: identityMode,
|
identity: identityMode,
|
||||||
mixed: mixedMode,
|
mixed: mixedMode,
|
||||||
|
@ -7052,8 +7054,7 @@ var IdentityHandler = {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ideally we'd just make this a Java string
|
result.encrypted = true;
|
||||||
result.encrypted = Strings.browser.GetStringFromName("identity.encrypted2");
|
|
||||||
result.host = this.getEffectiveHost();
|
result.host = this.getEffectiveHost();
|
||||||
|
|
||||||
let iData = this.getIdentityData();
|
let iData = this.getIdentityData();
|
||||||
|
|
|
@ -146,16 +146,24 @@ LoginManagerPrompter.prototype = {
|
||||||
* String message to be displayed in the doorhanger
|
* String message to be displayed in the doorhanger
|
||||||
* @param aButtons
|
* @param aButtons
|
||||||
* Buttons to display with the doorhanger
|
* Buttons to display with the doorhanger
|
||||||
* @param aActionText
|
* @param aUsername
|
||||||
* Object with text to be displayed as clickable, along with a bundle to create an action
|
* Username string used in creating a doorhanger action
|
||||||
*
|
* @param aPassword
|
||||||
|
* Password string used in creating a doorhanger action
|
||||||
*/
|
*/
|
||||||
_showLoginNotification : function (aTitle, aBody, aButtons, aActionText) {
|
_showLoginNotification : function (aTitle, aBody, aButtons, aUsername, aPassword) {
|
||||||
let notifyWin = this._window.top;
|
let notifyWin = this._window.top;
|
||||||
let chromeWin = this._getChromeWindow(notifyWin).wrappedJSObject;
|
let chromeWin = this._getChromeWindow(notifyWin).wrappedJSObject;
|
||||||
let browser = chromeWin.BrowserApp.getBrowserForWindow(notifyWin);
|
let browser = chromeWin.BrowserApp.getBrowserForWindow(notifyWin);
|
||||||
let tabID = chromeWin.BrowserApp.getTabForBrowser(browser).id;
|
let tabID = chromeWin.BrowserApp.getTabForBrowser(browser).id;
|
||||||
|
|
||||||
|
let actionText = {
|
||||||
|
text: aUsername,
|
||||||
|
type: "EDIT",
|
||||||
|
bundle: { username: aUsername,
|
||||||
|
password: aPassword }
|
||||||
|
};
|
||||||
|
|
||||||
// The page we're going to hasn't loaded yet, so we want to persist
|
// The page we're going to hasn't loaded yet, so we want to persist
|
||||||
// across the first location change.
|
// across the first location change.
|
||||||
|
|
||||||
|
@ -163,12 +171,11 @@ LoginManagerPrompter.prototype = {
|
||||||
// at the post-authentication page. I don't see a good way to
|
// at the post-authentication page. I don't see a good way to
|
||||||
// heuristically determine when to ignore such location changes, so
|
// heuristically determine when to ignore such location changes, so
|
||||||
// we'll try ignoring location changes based on a time interval.
|
// we'll try ignoring location changes based on a time interval.
|
||||||
|
|
||||||
let options = {
|
let options = {
|
||||||
persistWhileVisible: true,
|
persistWhileVisible: true,
|
||||||
timeout: Date.now() + 10000,
|
timeout: Date.now() + 10000,
|
||||||
title: aTitle,
|
title: aTitle,
|
||||||
actionText: aActionText
|
actionText: actionText
|
||||||
}
|
}
|
||||||
|
|
||||||
var nativeWindow = this._getNativeWindow();
|
var nativeWindow = this._getNativeWindow();
|
||||||
|
@ -194,13 +201,6 @@ LoginManagerPrompter.prototype = {
|
||||||
|
|
||||||
let username = aLogin.username ? this._sanitizeUsername(aLogin.username) : "";
|
let username = aLogin.username ? this._sanitizeUsername(aLogin.username) : "";
|
||||||
|
|
||||||
let actionText = {
|
|
||||||
text: username,
|
|
||||||
type: "EDIT",
|
|
||||||
bundle: { username: username,
|
|
||||||
password: aLogin.password }
|
|
||||||
};
|
|
||||||
|
|
||||||
// The callbacks in |buttons| have a closure to access the variables
|
// The callbacks in |buttons| have a closure to access the variables
|
||||||
// in scope here; set one to |this._pwmgr| so we can get back to pwmgr
|
// in scope here; set one to |this._pwmgr| so we can get back to pwmgr
|
||||||
// without a getService() call.
|
// without a getService() call.
|
||||||
|
@ -230,7 +230,7 @@ LoginManagerPrompter.prototype = {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
this._showLoginNotification(title, notificationText, buttons, actionText);
|
this._showLoginNotification(title, notificationText, buttons, aLogin.username, aLogin.password);
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -280,15 +280,17 @@ LoginManagerPrompter.prototype = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this._getLocalizedString("updateButton"),
|
label: this._getLocalizedString("updateButton"),
|
||||||
callback: function() {
|
callback: function(checked, response) {
|
||||||
self._updateLogin(aOldLogin, aNewPassword);
|
let password = response ? response["password"] : aNewPassword;
|
||||||
promptHistogram.add(PROMPT_UPDATE);
|
self._updateLogin(aOldLogin, password);
|
||||||
|
|
||||||
|
promptHistogram.add(PROMPT_UPDATE);
|
||||||
},
|
},
|
||||||
positive: true
|
positive: true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
this._showLoginNotification(title, notificationText, buttons);
|
this._showLoginNotification(title, notificationText, buttons, aOldLogin.username, aNewPassword);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,6 @@ identity.identified.verifier=Verified by: %S
|
||||||
identity.identified.verified_by_you=You have added a security exception for this site
|
identity.identified.verified_by_you=You have added a security exception for this site
|
||||||
identity.identified.state_and_country=%S, %S
|
identity.identified.state_and_country=%S, %S
|
||||||
identity.identified.title_with_country=%S (%S)
|
identity.identified.title_with_country=%S (%S)
|
||||||
identity.encrypted2=Encrypted
|
|
||||||
|
|
||||||
# Geolocation UI
|
# Geolocation UI
|
||||||
geolocation.allow=Share
|
geolocation.allow=Share
|
||||||
|
|
|
@ -193,6 +193,7 @@ public class StringHelper {
|
||||||
public final String SETTINGS_LABEL;
|
public final String SETTINGS_LABEL;
|
||||||
public final String GUEST_MODE_LABEL;
|
public final String GUEST_MODE_LABEL;
|
||||||
public final String TAB_QUEUE_LABEL;
|
public final String TAB_QUEUE_LABEL;
|
||||||
|
public final String TAB_QUEUE_SUMMARY;
|
||||||
|
|
||||||
// Android 3.0+
|
// Android 3.0+
|
||||||
public final String TOOLS_LABEL;
|
public final String TOOLS_LABEL;
|
||||||
|
@ -367,6 +368,7 @@ public class StringHelper {
|
||||||
SETTINGS_LABEL = res.getString(R.string.settings);
|
SETTINGS_LABEL = res.getString(R.string.settings);
|
||||||
GUEST_MODE_LABEL = res.getString(R.string.new_guest_session);
|
GUEST_MODE_LABEL = res.getString(R.string.new_guest_session);
|
||||||
TAB_QUEUE_LABEL = res.getString(R.string.pref_tab_queue_title);
|
TAB_QUEUE_LABEL = res.getString(R.string.pref_tab_queue_title);
|
||||||
|
TAB_QUEUE_SUMMARY = res.getString(R.string.pref_tab_queue_summary);
|
||||||
|
|
||||||
// Android 3.0+
|
// Android 3.0+
|
||||||
TOOLS_LABEL = res.getString(R.string.tools);
|
TOOLS_LABEL = res.getString(R.string.tools);
|
||||||
|
|
|
@ -206,8 +206,7 @@ public class testSettingsMenuItems extends PixelTest {
|
||||||
|
|
||||||
// Tab Queue
|
// Tab Queue
|
||||||
if (AppConstants.NIGHTLY_BUILD && AppConstants.MOZ_ANDROID_TAB_QUEUE) {
|
if (AppConstants.NIGHTLY_BUILD && AppConstants.MOZ_ANDROID_TAB_QUEUE) {
|
||||||
final String expected = "Queue links for later instead of switching to " + mStringHelper.BRAND_NAME + " each time";
|
final String[] tabQueue = { mStringHelper.TAB_QUEUE_LABEL, mStringHelper.TAB_QUEUE_SUMMARY };
|
||||||
String[] tabQueue = { mStringHelper.TAB_QUEUE_LABEL, expected };
|
|
||||||
settingsMap.get(PATH_CUSTOMIZE).add(tabQueue);
|
settingsMap.get(PATH_CUSTOMIZE).add(tabQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@ user_pref("experiments.manifest.uri", "http://%(server)s/experiments-dummy/manif
|
||||||
// Only load extensions from the application and user profile
|
// Only load extensions from the application and user profile
|
||||||
// AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
|
// AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
|
||||||
user_pref("extensions.enabledScopes", 5);
|
user_pref("extensions.enabledScopes", 5);
|
||||||
|
user_pref("extensions.autoDisableScopes", 0);
|
||||||
// Disable metadata caching for installed add-ons by default
|
// Disable metadata caching for installed add-ons by default
|
||||||
user_pref("extensions.getAddons.cache.enabled", false);
|
user_pref("extensions.getAddons.cache.enabled", false);
|
||||||
// Disable intalling any distribution add-ons
|
// Disable intalling any distribution add-ons
|
||||||
|
@ -325,3 +326,7 @@ user_pref("dom.serviceWorkers.periodic-updates.enabled", false);
|
||||||
|
|
||||||
// Enable speech synth test service, and disable built in platform services.
|
// Enable speech synth test service, and disable built in platform services.
|
||||||
user_pref("media.webspeech.synth.test", true);
|
user_pref("media.webspeech.synth.test", true);
|
||||||
|
|
||||||
|
// Turn off search suggestions in the location bar so as not to trigger network
|
||||||
|
// connections.
|
||||||
|
user_pref("browser.urlbar.suggest.searches", false);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
},
|
},
|
||||||
"global": {
|
"global": {
|
||||||
"talos_repo": "https://hg.mozilla.org/build/talos",
|
"talos_repo": "https://hg.mozilla.org/build/talos",
|
||||||
"talos_revision": "e04283e4f2b2"
|
"talos_revision": "4a8d22dd38c4"
|
||||||
},
|
},
|
||||||
"extra_options": {
|
"extra_options": {
|
||||||
"android": [ "--apkPath=%(apk_path)s" ]
|
"android": [ "--apkPath=%(apk_path)s" ]
|
||||||
|
|
|
@ -800,6 +800,20 @@ LoginManagerPrompter.prototype = {
|
||||||
|
|
||||||
let currentNotification;
|
let currentNotification;
|
||||||
|
|
||||||
|
let updateButtonStatus = (element) => {
|
||||||
|
let mainActionButton = chromeDoc.getAnonymousElementByAttribute(element.button, "anonid", "button");
|
||||||
|
// Disable the main button inside the menu-button if the password field is empty.
|
||||||
|
if (login.password.length == 0) {
|
||||||
|
mainActionButton.setAttribute("disabled", true);
|
||||||
|
chromeDoc.getElementById("password-notification-password")
|
||||||
|
.classList.add("popup-notification-invalid-input");
|
||||||
|
} else {
|
||||||
|
mainActionButton.removeAttribute("disabled");
|
||||||
|
chromeDoc.getElementById("password-notification-password")
|
||||||
|
.classList.remove("popup-notification-invalid-input");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let updateButtonLabel = () => {
|
let updateButtonLabel = () => {
|
||||||
let foundLogins = Services.logins.findLogins({}, login.hostname,
|
let foundLogins = Services.logins.findLogins({}, login.hostname,
|
||||||
login.formSubmitURL,
|
login.formSubmitURL,
|
||||||
|
@ -821,6 +835,7 @@ LoginManagerPrompter.prototype = {
|
||||||
if (element) {
|
if (element) {
|
||||||
element.setAttribute("buttonlabel", label);
|
element.setAttribute("buttonlabel", label);
|
||||||
element.setAttribute("buttonaccesskey", accessKey);
|
element.setAttribute("buttonaccesskey", accessKey);
|
||||||
|
updateButtonStatus(element);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -831,6 +846,8 @@ LoginManagerPrompter.prototype = {
|
||||||
.setAttribute("value", login.username);
|
.setAttribute("value", login.username);
|
||||||
chromeDoc.getElementById("password-notification-password")
|
chromeDoc.getElementById("password-notification-password")
|
||||||
.setAttribute("value", login.password);
|
.setAttribute("value", login.password);
|
||||||
|
chromeDoc.getElementById("password-notification-password")
|
||||||
|
.setAttribute("show-content", showPasswordPlaceholder);
|
||||||
updateButtonLabel();
|
updateButtonLabel();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -841,11 +858,19 @@ LoginManagerPrompter.prototype = {
|
||||||
chromeDoc.getElementById("password-notification-password").value;
|
chromeDoc.getElementById("password-notification-password").value;
|
||||||
};
|
};
|
||||||
|
|
||||||
let onUsernameInput = () => {
|
let onInput = () => {
|
||||||
readDataFromUI();
|
readDataFromUI();
|
||||||
updateButtonLabel();
|
updateButtonLabel();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let onPasswordFocus = () => {
|
||||||
|
chromeDoc.getElementById("password-notification-password").type = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
let onPasswordBlur = () => {
|
||||||
|
chromeDoc.getElementById("password-notification-password").type = "password";
|
||||||
|
};
|
||||||
|
|
||||||
let persistData = () => {
|
let persistData = () => {
|
||||||
let foundLogins = Services.logins.findLogins({}, login.hostname,
|
let foundLogins = Services.logins.findLogins({}, login.hostname,
|
||||||
login.formSubmitURL,
|
login.formSubmitURL,
|
||||||
|
@ -862,7 +887,12 @@ LoginManagerPrompter.prototype = {
|
||||||
login.usernameField,
|
login.usernameField,
|
||||||
login.passwordField));
|
login.passwordField));
|
||||||
} else if (logins.length == 1) {
|
} else if (logins.length == 1) {
|
||||||
this._updateLogin(logins[0], login.password);
|
if (logins[0].password == login.password) {
|
||||||
|
// We only want to touch the login's use count and last used time.
|
||||||
|
this._updateLogin(logins[0], null);
|
||||||
|
} else {
|
||||||
|
this._updateLogin(logins[0], login.password);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Cu.reportError("Unexpected match of multiple logins.");
|
Cu.reportError("Unexpected match of multiple logins.");
|
||||||
}
|
}
|
||||||
|
@ -896,6 +926,7 @@ LoginManagerPrompter.prototype = {
|
||||||
}] : null;
|
}] : null;
|
||||||
|
|
||||||
let usernamePlaceholder = this._getLocalizedString("noUsernamePlaceholder");
|
let usernamePlaceholder = this._getLocalizedString("noUsernamePlaceholder");
|
||||||
|
let showPasswordPlaceholder = this._getLocalizedString("showPasswordPlaceholder");
|
||||||
let displayHost = this._getShortDisplayHost(login.hostname);
|
let displayHost = this._getShortDisplayHost(login.hostname);
|
||||||
|
|
||||||
this._getPopupNote().show(
|
this._getPopupNote().show(
|
||||||
|
@ -913,9 +944,17 @@ LoginManagerPrompter.prototype = {
|
||||||
switch (topic) {
|
switch (topic) {
|
||||||
case "showing":
|
case "showing":
|
||||||
currentNotification = this;
|
currentNotification = this;
|
||||||
writeDataToUI();
|
|
||||||
chromeDoc.getElementById("password-notification-username")
|
chromeDoc.getElementById("password-notification-username")
|
||||||
.addEventListener("input", onUsernameInput);
|
.addEventListener("input", onInput);
|
||||||
|
chromeDoc.getElementById("password-notification-password")
|
||||||
|
.addEventListener("input", onInput);
|
||||||
|
chromeDoc.getElementById("password-notification-password")
|
||||||
|
.addEventListener("focus", onPasswordFocus);
|
||||||
|
chromeDoc.getElementById("password-notification-password")
|
||||||
|
.addEventListener("blur", onPasswordBlur);
|
||||||
|
break;
|
||||||
|
case "shown":
|
||||||
|
writeDataToUI();
|
||||||
break;
|
break;
|
||||||
case "dismissed":
|
case "dismissed":
|
||||||
readDataFromUI();
|
readDataFromUI();
|
||||||
|
@ -923,7 +962,13 @@ LoginManagerPrompter.prototype = {
|
||||||
case "removed":
|
case "removed":
|
||||||
currentNotification = null;
|
currentNotification = null;
|
||||||
chromeDoc.getElementById("password-notification-username")
|
chromeDoc.getElementById("password-notification-username")
|
||||||
.removeEventListener("input", onUsernameInput);
|
.removeEventListener("input", onInput);
|
||||||
|
chromeDoc.getElementById("password-notification-password")
|
||||||
|
.removeEventListener("input", onInput);
|
||||||
|
chromeDoc.getElementById("password-notification-password")
|
||||||
|
.removeEventListener("focus", onPasswordFocus);
|
||||||
|
chromeDoc.getElementById("password-notification-password")
|
||||||
|
.removeEventListener("blur", onPasswordBlur);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -635,9 +635,21 @@ AsyncFetchAndSetIconFromNetwork::OnStopRequest(nsIRequest* aRequest,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, aRequest,
|
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
|
||||||
TO_INTBUFFER(mIcon.data), mIcon.data.Length(),
|
// aRequest should always QI to nsIChannel.
|
||||||
mIcon.mimeType);
|
// See AsyncFetchAndSetIconFromNetwork::Run()
|
||||||
|
MOZ_ASSERT(channel);
|
||||||
|
|
||||||
|
nsAutoCString contentType;
|
||||||
|
channel->GetContentType(contentType);
|
||||||
|
// Bug 366324 - can't sniff SVG yet, so rely on server-specified type
|
||||||
|
if (contentType.EqualsLiteral("image/svg+xml")) {
|
||||||
|
mIcon.mimeType.AssignLiteral("image/svg+xml");
|
||||||
|
} else {
|
||||||
|
NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, aRequest,
|
||||||
|
TO_INTBUFFER(mIcon.data), mIcon.data.Length(),
|
||||||
|
mIcon.mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
// If the icon does not have a valid MIME type, add it to the failed cache.
|
// If the icon does not have a valid MIME type, add it to the failed cache.
|
||||||
if (mIcon.mimeType.IsEmpty()) {
|
if (mIcon.mimeType.IsEmpty()) {
|
||||||
|
@ -649,10 +661,6 @@ AsyncFetchAndSetIconFromNetwork::OnStopRequest(nsIRequest* aRequest,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
|
|
||||||
// aRequest should always QI to nsIChannel.
|
|
||||||
// See AsyncFetchAndSetIconFromNetwork::Run()
|
|
||||||
MOZ_ASSERT(channel);
|
|
||||||
mIcon.expiration = GetExpirationTimeFromChannel(channel);
|
mIcon.expiration = GetExpirationTimeFromChannel(channel);
|
||||||
|
|
||||||
// Telemetry probes to measure the favicon file sizes for each different file type.
|
// Telemetry probes to measure the favicon file sizes for each different file type.
|
||||||
|
|
|
@ -17,6 +17,9 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||||
Cu.import("resource://gre/modules/Task.jsm");
|
Cu.import("resource://gre/modules/Task.jsm");
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "SearchSuggestionController",
|
||||||
|
"resource://gre/modules/SearchSuggestionController.jsm");
|
||||||
|
|
||||||
const SEARCH_ENGINE_TOPIC = "browser-search-engine-modified";
|
const SEARCH_ENGINE_TOPIC = "browser-search-engine-modified";
|
||||||
|
|
||||||
const SearchAutocompleteProviderInternal = {
|
const SearchAutocompleteProviderInternal = {
|
||||||
|
@ -110,10 +113,65 @@ const SearchAutocompleteProviderInternal = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getSuggestionController(searchToken, inPrivateContext, maxResults) {
|
||||||
|
let engine = Services.search.currentEngine;
|
||||||
|
if (!engine) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new SearchSuggestionControllerWrapper(engine, searchToken,
|
||||||
|
inPrivateContext, maxResults);
|
||||||
|
},
|
||||||
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||||
Ci.nsISupportsWeakReference]),
|
Ci.nsISupportsWeakReference]),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function SearchSuggestionControllerWrapper(engine, searchToken,
|
||||||
|
inPrivateContext, maxResults) {
|
||||||
|
this._controller = new SearchSuggestionController();
|
||||||
|
this._controller.maxLocalResults = 0;
|
||||||
|
this._controller.maxRemoteResults = maxResults;
|
||||||
|
let promise = this._controller.fetch(searchToken, inPrivateContext, engine);
|
||||||
|
this._suggestions = [];
|
||||||
|
this._promise = promise.then(results => {
|
||||||
|
this._suggestions = (results ? results.remote : null) || [];
|
||||||
|
}).catch(err => {
|
||||||
|
// fetch() rejects its promise if there's a pending request.
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchSuggestionControllerWrapper.prototype = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolved when all suggestions have been fetched.
|
||||||
|
*/
|
||||||
|
get fetchCompletePromise() {
|
||||||
|
return this._promise;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns one suggestion, if any are available. The returned value is an
|
||||||
|
* array [match, suggestion]. If none are available, returns [null, null].
|
||||||
|
* Note that there are two reasons that suggestions might not be available:
|
||||||
|
* all suggestions may have been fetched and consumed, or the fetch may not
|
||||||
|
* have completed yet.
|
||||||
|
*
|
||||||
|
* @return An array [match, suggestion].
|
||||||
|
*/
|
||||||
|
consume() {
|
||||||
|
return !this._suggestions.length ? [null, null] :
|
||||||
|
[SearchAutocompleteProviderInternal.defaultMatch,
|
||||||
|
this._suggestions.shift()];
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the fetch.
|
||||||
|
*/
|
||||||
|
stop() {
|
||||||
|
this._controller.stop();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let gInitializationPromise = null;
|
let gInitializationPromise = null;
|
||||||
|
|
||||||
this.PlacesSearchAutocompleteProvider = Object.freeze({
|
this.PlacesSearchAutocompleteProvider = Object.freeze({
|
||||||
|
@ -214,4 +272,12 @@ this.PlacesSearchAutocompleteProvider = Object.freeze({
|
||||||
terms: parseUrlResult.terms,
|
terms: parseUrlResult.terms,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getSuggestionController(searchToken, inPrivateContext, maxResults) {
|
||||||
|
if (!SearchAutocompleteProviderInternal.initialized) {
|
||||||
|
throw new Error("The component has not been initialized.");
|
||||||
|
}
|
||||||
|
return SearchAutocompleteProviderInternal.getSuggestionController(
|
||||||
|
searchToken, inPrivateContext, maxResults);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -35,6 +35,7 @@ const PREF_SUGGEST_HISTORY = [ "suggest.history", true ];
|
||||||
const PREF_SUGGEST_BOOKMARK = [ "suggest.bookmark", true ];
|
const PREF_SUGGEST_BOOKMARK = [ "suggest.bookmark", true ];
|
||||||
const PREF_SUGGEST_OPENPAGE = [ "suggest.openpage", true ];
|
const PREF_SUGGEST_OPENPAGE = [ "suggest.openpage", true ];
|
||||||
const PREF_SUGGEST_HISTORY_ONLYTYPED = [ "suggest.history.onlyTyped", false ];
|
const PREF_SUGGEST_HISTORY_ONLYTYPED = [ "suggest.history.onlyTyped", false ];
|
||||||
|
const PREF_SUGGEST_SEARCHES = [ "suggest.searches", true ];
|
||||||
|
|
||||||
// Match type constants.
|
// Match type constants.
|
||||||
// These indicate what type of search function we should be using.
|
// These indicate what type of search function we should be using.
|
||||||
|
@ -65,6 +66,13 @@ const TELEMETRY_6_FIRST_RESULTS = "PLACES_AUTOCOMPLETE_6_FIRST_RESULTS_TIME_MS";
|
||||||
// The default frecency value used when inserting matches with unknown frecency.
|
// The default frecency value used when inserting matches with unknown frecency.
|
||||||
const FRECENCY_DEFAULT = 1000;
|
const FRECENCY_DEFAULT = 1000;
|
||||||
|
|
||||||
|
// Search suggestion results are mixed in with all other results after they
|
||||||
|
// become available, but they're only inserted once every N results whose
|
||||||
|
// frecencies are less than FRECENCY_DEFAULT. In other words, for every N
|
||||||
|
// results that fall below that frecency threshold, one search suggestion is
|
||||||
|
// inserted. This value = N.
|
||||||
|
const SEARCH_SUGGESTION_INSERT_INTERVAL = 2;
|
||||||
|
|
||||||
// A regex that matches "single word" hostnames for whitelisting purposes.
|
// A regex that matches "single word" hostnames for whitelisting purposes.
|
||||||
// The hostname will already have been checked for general validity, so we
|
// The hostname will already have been checked for general validity, so we
|
||||||
// don't need to be exhaustive here, so allow dashes anywhere.
|
// don't need to be exhaustive here, so allow dashes anywhere.
|
||||||
|
@ -344,10 +352,15 @@ XPCOMUtils.defineLazyGetter(this, "SwitchToTabStorage", () => Object.seal({
|
||||||
*/
|
*/
|
||||||
XPCOMUtils.defineLazyGetter(this, "Prefs", () => {
|
XPCOMUtils.defineLazyGetter(this, "Prefs", () => {
|
||||||
let prefs = new Preferences(PREF_BRANCH);
|
let prefs = new Preferences(PREF_BRANCH);
|
||||||
let types = ["History", "Bookmark", "Openpage", "Typed"];
|
let types = ["History", "Bookmark", "Openpage", "Typed", "Searches"];
|
||||||
|
|
||||||
function syncEnabledPref(init = false) {
|
function syncEnabledPref(init = false) {
|
||||||
let suggestPrefs = [PREF_SUGGEST_HISTORY, PREF_SUGGEST_BOOKMARK, PREF_SUGGEST_OPENPAGE];
|
let suggestPrefs = [
|
||||||
|
PREF_SUGGEST_HISTORY,
|
||||||
|
PREF_SUGGEST_BOOKMARK,
|
||||||
|
PREF_SUGGEST_OPENPAGE,
|
||||||
|
PREF_SUGGEST_SEARCHES,
|
||||||
|
];
|
||||||
|
|
||||||
if (init) {
|
if (init) {
|
||||||
// Make sure to initialize the properties when first called with init = true.
|
// Make sure to initialize the properties when first called with init = true.
|
||||||
|
@ -356,6 +369,7 @@ XPCOMUtils.defineLazyGetter(this, "Prefs", () => {
|
||||||
store.suggestBookmark = prefs.get(...PREF_SUGGEST_BOOKMARK);
|
store.suggestBookmark = prefs.get(...PREF_SUGGEST_BOOKMARK);
|
||||||
store.suggestOpenpage = prefs.get(...PREF_SUGGEST_OPENPAGE);
|
store.suggestOpenpage = prefs.get(...PREF_SUGGEST_OPENPAGE);
|
||||||
store.suggestTyped = prefs.get(...PREF_SUGGEST_HISTORY_ONLYTYPED);
|
store.suggestTyped = prefs.get(...PREF_SUGGEST_HISTORY_ONLYTYPED);
|
||||||
|
store.suggestSearches = prefs.get(...PREF_SUGGEST_SEARCHES);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (store.enabled) {
|
if (store.enabled) {
|
||||||
|
@ -395,6 +409,7 @@ XPCOMUtils.defineLazyGetter(this, "Prefs", () => {
|
||||||
store.suggestBookmark = prefs.get(...PREF_SUGGEST_BOOKMARK);
|
store.suggestBookmark = prefs.get(...PREF_SUGGEST_BOOKMARK);
|
||||||
store.suggestOpenpage = prefs.get(...PREF_SUGGEST_OPENPAGE);
|
store.suggestOpenpage = prefs.get(...PREF_SUGGEST_OPENPAGE);
|
||||||
store.suggestTyped = prefs.get(...PREF_SUGGEST_HISTORY_ONLYTYPED);
|
store.suggestTyped = prefs.get(...PREF_SUGGEST_HISTORY_ONLYTYPED);
|
||||||
|
store.suggestSearches = prefs.get(...PREF_SUGGEST_SEARCHES);
|
||||||
|
|
||||||
// If history is not set, onlyTyped value should be ignored.
|
// If history is not set, onlyTyped value should be ignored.
|
||||||
if (!store.suggestHistory) {
|
if (!store.suggestHistory) {
|
||||||
|
@ -566,6 +581,7 @@ function Search(searchString, searchParam, autocompleteListener,
|
||||||
let params = new Set(searchParam.split(" "));
|
let params = new Set(searchParam.split(" "));
|
||||||
this._enableActions = params.has("enable-actions");
|
this._enableActions = params.has("enable-actions");
|
||||||
this._disablePrivateActions = params.has("disable-private-actions");
|
this._disablePrivateActions = params.has("disable-private-actions");
|
||||||
|
this._inPrivateWindow = params.has("private-window");
|
||||||
|
|
||||||
this._searchTokens =
|
this._searchTokens =
|
||||||
this.filterTokens(getUnfilteredSearchTokens(this._searchString));
|
this.filterTokens(getUnfilteredSearchTokens(this._searchString));
|
||||||
|
@ -599,6 +615,8 @@ function Search(searchString, searchParam, autocompleteListener,
|
||||||
// These are used to avoid adding duplicate entries to the results.
|
// These are used to avoid adding duplicate entries to the results.
|
||||||
this._usedURLs = new Set();
|
this._usedURLs = new Set();
|
||||||
this._usedPlaceIds = new Set();
|
this._usedPlaceIds = new Set();
|
||||||
|
|
||||||
|
this._searchSuggestionInsertCounter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Search.prototype = {
|
Search.prototype = {
|
||||||
|
@ -704,6 +722,10 @@ Search.prototype = {
|
||||||
this._sleepDeferred.resolve();
|
this._sleepDeferred.resolve();
|
||||||
this._sleepDeferred = null;
|
this._sleepDeferred = null;
|
||||||
}
|
}
|
||||||
|
if (this._searchSuggestionController) {
|
||||||
|
this._searchSuggestionController.stop();
|
||||||
|
this._searchSuggestionController = null;
|
||||||
|
}
|
||||||
this.pending = false;
|
this.pending = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -806,7 +828,22 @@ Search.prototype = {
|
||||||
// IMPORTANT: No other first result heuristics should run after
|
// IMPORTANT: No other first result heuristics should run after
|
||||||
// _matchHeuristicFallback().
|
// _matchHeuristicFallback().
|
||||||
|
|
||||||
yield this._sleep(Prefs.delay);
|
yield this._sleep(Math.round(Prefs.delay / 2));
|
||||||
|
if (!this.pending)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Start fetching search suggestions a little earlier than Prefs.delay since
|
||||||
|
// they're remote and will probably take longer to arrive.
|
||||||
|
if (this.hasBehavior("searches")) {
|
||||||
|
this._searchSuggestionController =
|
||||||
|
PlacesSearchAutocompleteProvider.getSuggestionController(
|
||||||
|
this._originalSearchString,
|
||||||
|
this._inPrivateWindow,
|
||||||
|
Prefs.maxRichResults
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
yield this._sleep(Math.round(Prefs.delay / 2));
|
||||||
if (!this.pending)
|
if (!this.pending)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -837,6 +874,13 @@ Search.prototype = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we still don't have enough results, fill the remaining space with
|
||||||
|
// search suggestions.
|
||||||
|
if (this._searchSuggestionController && this.pending) {
|
||||||
|
yield this._searchSuggestionController.fetchCompletePromise;
|
||||||
|
while (this.pending && this._maybeAddSearchSuggestionMatch());
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
_matchKnownUrl: function* (conn, queries) {
|
_matchKnownUrl: function* (conn, queries) {
|
||||||
|
@ -966,7 +1010,7 @@ Search.prototype = {
|
||||||
match.engineAlias = alias;
|
match.engineAlias = alias;
|
||||||
let query = this._searchTokens.slice(1).join(" ");
|
let query = this._searchTokens.slice(1).join(" ");
|
||||||
|
|
||||||
yield this._addSearchEngineMatch(match, query);
|
this._addSearchEngineMatch(match, query);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -976,16 +1020,17 @@ Search.prototype = {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let query = this._originalSearchString;
|
let query = this._originalSearchString;
|
||||||
|
this._addSearchEngineMatch(match, query);
|
||||||
yield this._addSearchEngineMatch(match, query);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_addSearchEngineMatch: function* (match, query) {
|
_addSearchEngineMatch(match, query, suggestion) {
|
||||||
let actionURLParams = {
|
let actionURLParams = {
|
||||||
engineName: match.engineName,
|
engineName: match.engineName,
|
||||||
input: this._originalSearchString,
|
input: this._originalSearchString,
|
||||||
searchQuery: query,
|
searchQuery: query,
|
||||||
};
|
};
|
||||||
|
if (suggestion)
|
||||||
|
actionURLParams.searchSuggestion = suggestion;
|
||||||
if (match.engineAlias) {
|
if (match.engineAlias) {
|
||||||
actionURLParams.alias = match.engineAlias;
|
actionURLParams.alias = match.engineAlias;
|
||||||
}
|
}
|
||||||
|
@ -1129,12 +1174,43 @@ Search.prototype = {
|
||||||
parseResult.engineName;
|
parseResult.engineName;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_maybeAddSearchSuggestionMatch() {
|
||||||
|
if (this._searchSuggestionController) {
|
||||||
|
let [match, suggestion] = this._searchSuggestionController.consume();
|
||||||
|
if (suggestion) {
|
||||||
|
this._addSearchEngineMatch(match, this._originalSearchString,
|
||||||
|
suggestion);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
_addMatch: function (match) {
|
_addMatch: function (match) {
|
||||||
// A search could be canceled between a query start and its completion,
|
// A search could be canceled between a query start and its completion,
|
||||||
// in such a case ensure we won't notify any result for it.
|
// in such a case ensure we won't notify any result for it.
|
||||||
if (!this.pending)
|
if (!this.pending)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Mix in search suggestions. Insert one suggestion every N non-suggestion
|
||||||
|
// matches that fall below the default frecency, and start inserting them as
|
||||||
|
// soon as they become available. N = SEARCH_SUGGESTION_INSERT_INTERVAL.
|
||||||
|
if (match.frecency < FRECENCY_DEFAULT) {
|
||||||
|
if (this._searchSuggestionInsertCounter %
|
||||||
|
SEARCH_SUGGESTION_INSERT_INTERVAL == 0) {
|
||||||
|
// Search engine matches are created with FRECENCY_DEFAULT, so there's
|
||||||
|
// no danger of infinite indirect recursion.
|
||||||
|
if (this._maybeAddSearchSuggestionMatch()) {
|
||||||
|
if (!this.pending) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._searchSuggestionInsertCounter++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._searchSuggestionInsertCounter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let notifyResults = false;
|
let notifyResults = false;
|
||||||
|
|
||||||
// Must check both id and url, cause keywords dinamically modify the url.
|
// Must check both id and url, cause keywords dinamically modify the url.
|
||||||
|
|
|
@ -13,7 +13,7 @@ interface nsIURI;
|
||||||
* search provider as well as methods to track opened pages for AutoComplete
|
* search provider as well as methods to track opened pages for AutoComplete
|
||||||
* purposes.
|
* purposes.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(6e252399-77f9-4f11-98cc-6fa9fab96f92)]
|
[scriptable, uuid(61b6348a-09e1-4810-8057-f8cb3cec6ef8)]
|
||||||
interface mozIPlacesAutoComplete : nsISupports
|
interface mozIPlacesAutoComplete : nsISupports
|
||||||
{
|
{
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -102,6 +102,11 @@ interface mozIPlacesAutoComplete : nsISupports
|
||||||
*/
|
*/
|
||||||
const long BEHAVIOR_RESTRICT = 1 << 8;
|
const long BEHAVIOR_RESTRICT = 1 << 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Include search suggestions from the currently selected search provider.
|
||||||
|
*/
|
||||||
|
const long BEHAVIOR_SEARCHES = 1 << 9;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark a page as being currently open.
|
* Mark a page as being currently open.
|
||||||
*
|
*
|
||||||
|
|
|
@ -57,6 +57,16 @@ XPCOMUtils.defineLazyGetter(this, "SMALLPNG_DATA_URI", function() {
|
||||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAA" +
|
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAA" +
|
||||||
"AAAA6fptVAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==");
|
"AAAA6fptVAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==");
|
||||||
});
|
});
|
||||||
|
XPCOMUtils.defineLazyGetter(this, "SMALLSVG_DATA_URI", function() {
|
||||||
|
return NetUtil.newURI(
|
||||||
|
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy5" +
|
||||||
|
"3My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIiBmaWxs" +
|
||||||
|
"PSIjNDI0ZTVhIj4NCiAgPGNpcmNsZSBjeD0iNTAiIGN5PSI1MCIgcj0iN" +
|
||||||
|
"DQiIHN0cm9rZT0iIzQyNGU1YSIgc3Ryb2tlLXdpZHRoPSIxMSIgZmlsbD" +
|
||||||
|
"0ibm9uZSIvPg0KICA8Y2lyY2xlIGN4PSI1MCIgY3k9IjI0LjYiIHI9IjY" +
|
||||||
|
"uNCIvPg0KICA8cmVjdCB4PSI0NSIgeT0iMzkuOSIgd2lkdGg9IjEwLjEi" +
|
||||||
|
"IGhlaWdodD0iNDEuOCIvPg0KPC9zdmc%2BDQo%3D");
|
||||||
|
});
|
||||||
|
|
||||||
let gTestDir = do_get_cwd();
|
let gTestDir = do_get_cwd();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
const PAGEURI = NetUtil.newURI("http://deliciousbacon.com/");
|
||||||
|
|
||||||
|
add_task(function* () {
|
||||||
|
// First, add a history entry or else Places can't save a favicon.
|
||||||
|
yield PlacesTestUtils.addVisits({
|
||||||
|
uri: PAGEURI,
|
||||||
|
transition: TRANSITION_LINK,
|
||||||
|
visitDate: Date.now() * 1000
|
||||||
|
});
|
||||||
|
|
||||||
|
yield new Promise(resolve => {
|
||||||
|
function onSetComplete(aURI, aDataLen, aData, aMimeType) {
|
||||||
|
equal(aURI.spec, SMALLSVG_DATA_URI.spec, "setFavicon aURI check");
|
||||||
|
equal(aDataLen, 263, "setFavicon aDataLen check");
|
||||||
|
equal(aMimeType, "image/svg+xml", "setFavicon aMimeType check");
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
PlacesUtils.favicons.setAndFetchFaviconForPage(PAGEURI, SMALLSVG_DATA_URI,
|
||||||
|
false,
|
||||||
|
PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
|
||||||
|
onSetComplete);
|
||||||
|
});
|
||||||
|
|
||||||
|
let data = yield PlacesUtils.promiseFaviconData(PAGEURI.spec);
|
||||||
|
equal(data.uri.spec, SMALLSVG_DATA_URI.spec, "getFavicon aURI check");
|
||||||
|
equal(data.dataLen, 263, "getFavicon aDataLen check");
|
||||||
|
equal(data.mimeType, "image/svg+xml", "getFavicon aMimeType check");
|
||||||
|
});
|
||||||
|
|
|
@ -138,6 +138,7 @@ skip-if = os == "android"
|
||||||
[test_resolveNullBookmarkTitles.js]
|
[test_resolveNullBookmarkTitles.js]
|
||||||
[test_result_sort.js]
|
[test_result_sort.js]
|
||||||
[test_sql_guid_functions.js]
|
[test_sql_guid_functions.js]
|
||||||
|
[test_svg_favicon.js]
|
||||||
[test_tag_autocomplete_search.js]
|
[test_tag_autocomplete_search.js]
|
||||||
[test_tagging.js]
|
[test_tagging.js]
|
||||||
[test_telemetry.js]
|
[test_telemetry.js]
|
||||||
|
|
|
@ -11,3 +11,7 @@
|
||||||
image-rendering: -moz-crisp-edges;
|
image-rendering: -moz-crisp-edges;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
richlistitem > .ac-title-box > .ac-title > .ac-comment:not([selected]) > html|span.ac-selected-text {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
|
@ -1539,11 +1539,10 @@ extends="chrome://global/content/bindings/popup.xml#popup">
|
||||||
let index = (match[1] || 1) - 1;
|
let index = (match[1] || 1) - 1;
|
||||||
|
|
||||||
if (index >= 0 && index < aReplacements.length) {
|
if (index >= 0 && index < aReplacements.length) {
|
||||||
let replacement = aReplacements[index];
|
pairs.push([...aReplacements[index]]);
|
||||||
pairs.push([...replacement]);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pairs.push([part, false]);
|
pairs.push([part]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1572,8 +1571,15 @@ extends="chrome://global/content/bindings/popup.xml#popup">
|
||||||
if (emphasise) {
|
if (emphasise) {
|
||||||
let span = aDescriptionElement.appendChild(
|
let span = aDescriptionElement.appendChild(
|
||||||
document.createElementNS("http://www.w3.org/1999/xhtml", "span"));
|
document.createElementNS("http://www.w3.org/1999/xhtml", "span"));
|
||||||
span.className = "ac-emphasize-text";
|
|
||||||
span.textContent = text;
|
span.textContent = text;
|
||||||
|
switch(emphasise) {
|
||||||
|
case "match":
|
||||||
|
span.className = "ac-emphasize-text";
|
||||||
|
break;
|
||||||
|
case "selected":
|
||||||
|
span.className = "ac-selected-text";
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
aDescriptionElement.appendChild(document.createTextNode(text));
|
aDescriptionElement.appendChild(document.createTextNode(text));
|
||||||
}
|
}
|
||||||
|
@ -1629,10 +1635,22 @@ extends="chrome://global/content/bindings/popup.xml#popup">
|
||||||
} else if (action.type == "searchengine") {
|
} else if (action.type == "searchengine") {
|
||||||
emphasiseUrl = false;
|
emphasiseUrl = false;
|
||||||
|
|
||||||
let sourceStr = this._stringBundle.GetStringFromName("searchWithEngineForQuery");
|
// The order here is not localizable, we default to appending
|
||||||
title = this._generateEmphasisPairs(sourceStr, [
|
// "- Search with Engine" to the search string, to be able to
|
||||||
[action.params.engineName, false],
|
// properly generate emphasis pairs. That said, no localization
|
||||||
[action.params.searchQuery, true]
|
// changed the order while it was possible, so doesn't look like
|
||||||
|
// there's a strong need for that.
|
||||||
|
let {engineName, searchSuggestion, searchQuery} = action.params;
|
||||||
|
let engineStr = "- " +
|
||||||
|
this._stringBundle.formatStringFromName("searchWithEngine",
|
||||||
|
[engineName], 1);
|
||||||
|
let suggestedPart = "";
|
||||||
|
if (searchSuggestion) {
|
||||||
|
suggestedPart = searchSuggestion.substr(searchQuery.length);
|
||||||
|
}
|
||||||
|
title = this._generateEmphasisPairs(`%1$S${suggestedPart} %2$S`, [
|
||||||
|
[searchQuery, "match"],
|
||||||
|
[engineStr, "selected"],
|
||||||
]);
|
]);
|
||||||
// If this is a default search match, we remove the image so we
|
// If this is a default search match, we remove the image so we
|
||||||
// can style it ourselves with a generic search icon.
|
// can style it ourselves with a generic search icon.
|
||||||
|
@ -1649,7 +1667,7 @@ extends="chrome://global/content/bindings/popup.xml#popup">
|
||||||
|
|
||||||
let sourceStr = this._stringBundle.GetStringFromName("visitURL");
|
let sourceStr = this._stringBundle.GetStringFromName("visitURL");
|
||||||
title = this._generateEmphasisPairs(sourceStr, [
|
title = this._generateEmphasisPairs(sourceStr, [
|
||||||
[displayUrl, true],
|
[displayUrl, "match"],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1679,7 +1697,7 @@ extends="chrome://global/content/bindings/popup.xml#popup">
|
||||||
|
|
||||||
let sourceStr = this._stringBundle.GetStringFromName("visitURL");
|
let sourceStr = this._stringBundle.GetStringFromName("visitURL");
|
||||||
title = this._generateEmphasisPairs(sourceStr, [
|
title = this._generateEmphasisPairs(sourceStr, [
|
||||||
[displayUrl, true],
|
[displayUrl, "match"],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
types.delete("autofill");
|
types.delete("autofill");
|
||||||
|
|
|
@ -38,7 +38,8 @@ exports.safeErrorString = function safeErrorString(aError) {
|
||||||
}
|
}
|
||||||
} catch (ee) { }
|
} catch (ee) { }
|
||||||
|
|
||||||
return "<failed trying to find error description>";
|
// We failed to find a good error description, so do the next best thing.
|
||||||
|
return Object.prototype.toString.call(aError);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|