Merge fx-team to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-08-01 15:34:58 -04:00
commit a5dbe7697d
76 changed files with 1113 additions and 266 deletions

View File

@ -1455,7 +1455,7 @@ pref("devtools.browserconsole.filter.secwarn", true);
pref("devtools.webconsole.fontSize", 0);
// Number of usages of the web console or scratchpad.
// If this is less than 10, then pasting code into the web console or scratchpad is disabled
// If this is less than 5, then pasting code into the web console or scratchpad is disabled
pref("devtools.selfxss.count", 0);
// Persistent logging: |true| if you want the Web Console to keep all of the

View File

@ -7,6 +7,7 @@
#ifdef XP_MACOSX
<?xul-overlay href="chrome://browser/content/macBrowserOverlay.xul"?>
<?xml-stylesheet href="chrome://browser/skin/webRTC-indicator.css" type="text/css"?>
<window id="main-window"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"

View File

@ -317,6 +317,7 @@
openUILinkIn(url, "current", {
allowThirdPartyFixup: true,
disallowInheritPrincipal: !mayInheritPrincipal,
allowPinnedTabHostChange: true,
postData: postData
});
}

View File

@ -185,6 +185,7 @@ function whereToOpenLink( e, ignoreButton, ignoreAlt )
* referrerURI (nsIURI)
* relatedToCurrent (boolean)
* skipTabAnimation (boolean)
* allowPinnedTabHostChange (boolean)
*/
function openUILinkIn(url, where, aAllowThirdPartyFixup, aPostData, aReferrerURI) {
var params;
@ -220,6 +221,7 @@ function openLinkIn(url, where, params) {
var aInitiatingDoc = params.initiatingDoc;
var aIsPrivate = params.private;
var aSkipTabAnimation = params.skipTabAnimation;
var aAllowPinnedTabHostChange = !!params.allowPinnedTabHostChange;
if (where == "save") {
if (!aInitiatingDoc) {
@ -288,7 +290,8 @@ function openLinkIn(url, where, params) {
} catch (e) {}
}
if (where == "current" && w.gBrowser.selectedTab.pinned) {
if (where == "current" && w.gBrowser.selectedTab.pinned &&
!aAllowPinnedTabHostChange) {
try {
// nsIURI.host can throw for non-nsStandardURL nsIURIs.
if (!uriObj || (!uriObj.schemeIs("javascript") &&

View File

@ -25,8 +25,9 @@ function init(event) {
popup.addEventListener("command", onPopupMenuCommand);
}
document.getElementById("firefoxButton")
.addEventListener("click", onFirefoxButtonClick);
let fxButton = document.getElementById("firefoxButton");
fxButton.addEventListener("click", onFirefoxButtonClick);
fxButton.addEventListener("mousedown", PositionHandler);
updateIndicatorState();
}
@ -65,9 +66,10 @@ function updateIndicatorState() {
screenShareButton.removeAttribute("tooltiptext");
}
// Resize and center the window.
// Resize and ensure the window position is correct
// (sizeToContent messes with our position).
window.sizeToContent();
window.moveTo((screen.availWidth - document.documentElement.clientWidth) / 2, 0);
PositionHandler.adjustPosition();
}
function updateWindowAttr(attr, value) {
@ -90,7 +92,8 @@ function onPopupMenuShowing(event) {
if (activeStreams.length == 1) {
webrtcUI.showSharingDoorhanger(activeStreams[0], type);
return false;
event.preventDefault();
return;
}
for (let stream of activeStreams) {
@ -100,8 +103,6 @@ function onPopupMenuShowing(event) {
item.stream = stream;
popup.appendChild(item);
}
return true;
}
function onPopupMenuHiding(event) {
@ -121,3 +122,55 @@ function onFirefoxButtonClick(event) {
let activeStreams = webrtcUI.getActiveStreams(true, true, true);
activeStreams[0].browser.ownerDocument.defaultView.focus();
}
let PositionHandler = {
positionCustomized: false,
threshold: 10,
adjustPosition: function() {
if (!this.positionCustomized) {
// Center the window horizontally on the screen (not the available area).
window.moveTo((screen.width - document.documentElement.clientWidth) / 2, 0);
} else {
// This will ensure we're at y=0.
this.setXPosition(window.screenX);
}
},
setXPosition: function(desiredX) {
// Ensure the indicator isn't moved outside the available area of the screen.
let desiredX = Math.max(desiredX, screen.availLeft);
let maxX =
screen.availLeft + screen.availWidth - document.documentElement.clientWidth;
window.moveTo(Math.min(desiredX, maxX), 0);
},
handleEvent: function(aEvent) {
switch (aEvent.type) {
case "mousedown":
if (aEvent.button != 0 || aEvent.defaultPrevented)
return;
this._startMouseX = aEvent.screenX;
this._startWindowX = window.screenX;
this._deltaX = this._startMouseX - this._startWindowX;
window.addEventListener("mousemove", this);
window.addEventListener("mouseup", this);
break;
case "mousemove":
let moveOffset = Math.abs(aEvent.screenX - this._startMouseX);
if (this._dragFullyStarted || moveOffset > this.threshold) {
this.setXPosition(aEvent.screenX - this._deltaX);
this._dragFullyStarted = true;
}
break;
case "mouseup":
this._dragFullyStarted = false;
window.removeEventListener("mousemove", this);
window.removeEventListener("mouseup", this);
this.positionCustomized =
Math.abs(this._startWindowX - window.screenX) >= this.threshold;
break;
}
}
};

View File

@ -32,8 +32,8 @@ this.Translation = {
serviceUnavailable: false,
supportedSourceLanguages: ["zh", "de", "en", "fr", "ja", "ko", "pt", "ru", "es"],
supportedTargetLanguages: ["zh", "de", "en", "fr", "ja", "ko", "pt", "ru", "es"],
supportedSourceLanguages: ["de", "en", "es", "fr", "ja", "ko", "pt", "ru", "zh"],
supportedTargetLanguages: ["de", "en", "es", "fr", "ja", "ko", "pl", "pt", "ru", "tr", "vi", "zh"],
_defaultTargetLanguage: "",
get defaultTargetLanguage() {

View File

@ -166,12 +166,17 @@
let bundle = Cc["@mozilla.org/intl/stringbundle;1"]
.getService(Ci.nsIStringBundleService)
.createBundle("chrome://global/locale/languageNames.properties");
let sortByLocalizedName = function(aList) {
return aList.map(code => [code, bundle.GetStringFromName(code)])
.sort((a, b) => a[1].localeCompare(b[1]));
};
// Fill the lists of supported source languages.
let detectedLanguage = this._getAnonElt("detectedLanguage");
let fromLanguage = this._getAnonElt("fromLanguage");
for (let code of Translation.supportedSourceLanguages) {
let name = bundle.GetStringFromName(code);
let sourceLanguages =
sortByLocalizedName(Translation.supportedSourceLanguages);
for (let [code, name] of sourceLanguages) {
detectedLanguage.appendItem(name, code);
fromLanguage.appendItem(name, code);
}
@ -183,8 +188,10 @@
// Fill the list of supported target languages.
let toLanguage = this._getAnonElt("toLanguage");
for (let code of Translation.supportedTargetLanguages)
toLanguage.appendItem(bundle.GetStringFromName(code), code);
let targetLanguages =
sortByLocalizedName(Translation.supportedTargetLanguages);
for (let [code, name] of targetLanguages)
toLanguage.appendItem(name, code);
if (aTranslation.translatedTo)
toLanguage.value = aTranslation.translatedTo;

View File

@ -88,6 +88,8 @@ HTMLBreadcrumbs.prototype = {
this.container.addEventListener("mousedown", this, true);
this.container.addEventListener("keypress", this, true);
this.container.addEventListener("mouseover", this, true);
this.container.addEventListener("mouseleave", this, true);
// We will save a list of already displayed nodes in this array.
this.nodeHierarchy = [];
@ -373,6 +375,17 @@ HTMLBreadcrumbs.prototype = {
event.preventDefault();
event.stopPropagation();
}
if (event.type == "mouseover") {
let target = event.originalTarget;
if (target.tagName == "button") {
target.onBreadcrumbsHover();
}
}
if (event.type == "mouseleave") {
this.inspector.toolbox.highlighterUtils.unhighlight();
}
},
/**
@ -392,6 +405,8 @@ HTMLBreadcrumbs.prototype = {
this.empty();
this.container.removeEventListener("mousedown", this, true);
this.container.removeEventListener("keypress", this, true);
this.container.removeEventListener("mouseover", this, true);
this.container.removeEventListener("mouseleave", this, true);
this.container = null;
this.separators.remove();
@ -486,6 +501,10 @@ HTMLBreadcrumbs.prototype = {
this.selection.setNodeFront(aNode, "breadcrumbs");
};
button.onBreadcrumbsHover = () => {
this.inspector.toolbox.highlighterUtils.highlightNodeFront(aNode);
};
button.onclick = (function _onBreadcrumbsRightClick(event) {
button.focus();
if (event.button == 2) {

View File

@ -20,6 +20,7 @@ support-files =
head.js
[browser_inspector_breadcrumbs.js]
[browser_inspector_breadcrumbs_highlight_hover.js]
[browser_inspector_delete-selected-node-01.js]
[browser_inspector_delete-selected-node-02.js]
[browser_inspector_delete-selected-node-03.js]

View File

@ -0,0 +1,32 @@
/* 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";
// Test that hovering over nodes on the breadcrumb buttons in the inspector shows the highlighter over
// those nodes
let test = asyncTest(function*() {
info("Loading the test document and opening the inspector");
yield addTab("data:text/html;charset=utf-8,<h1>foo</h1><span>bar</span>");
let {toolbox, inspector} = yield openInspector();
info("Selecting the test node");
yield selectNode("span", inspector);
let bcButtons = inspector.breadcrumbs["container"];
let onNodeHighlighted = toolbox.once("node-highlight");
let button = bcButtons.childNodes[1];
EventUtils.synthesizeMouseAtCenter(button, {type: "mousemove"}, button.ownerDocument.defaultView);
yield onNodeHighlighted;
ok(isHighlighting(), "The highlighter is shown on a markup container hover");
is(getHighlitNode(), getNode("body"), "The highlighter highlights the right node");
let onNodeHighlighted = toolbox.once("node-highlight");
let button = bcButtons.childNodes[2];
EventUtils.synthesizeMouseAtCenter(button, {type: "mousemove"}, button.ownerDocument.defaultView);
yield onNodeHighlighted;
ok(isHighlighting(), "The highlighter is shown on a markup container hover");
is(getHighlitNode(), getNode("span"), "The highlighter highlights the right node");
gBrowser.removeCurrentTab();
});

View File

@ -52,11 +52,11 @@ function consoleOpened(HUD) {
WebConsoleUtils.usageCount = 0;
is(WebConsoleUtils.usageCount, 0, "Test for usage count getter")
// Input some commands to check if usage counting is working
for(let i = 0; i <= 5; i++){
for(let i = 0; i <= 3; i++){
jsterm.setInputValue(i);
jsterm.execute();
}
is(WebConsoleUtils.usageCount, 6, "Usage count incremented")
is(WebConsoleUtils.usageCount, 4, "Usage count incremented")
WebConsoleUtils.usageCount = 0;
updateEditUIVisibility();

View File

@ -513,8 +513,11 @@ function getGlobalIndicator() {
let field = "_" + aName.toLowerCase();
if (aState && !this[field]) {
let menu = this._hiddenDoc.createElement("menu");
let uri = "chrome://browser/skin/webRTC-" + aName.toLowerCase() + "-black-16.png";
menu.setAttribute("image", uri);
menu.setAttribute("id", "webRTC-sharing" + aName + "-menu");
// The CSS will only be applied if the menu is actually inserted in the DOM.
this._hiddenDoc.documentElement.appendChild(menu);
this._statusBar.addItem(menu);
let menupopup = this._hiddenDoc.createElement("menupopup");
@ -528,6 +531,7 @@ function getGlobalIndicator() {
}
else if (this[field] && !aState) {
this._statusBar.removeItem(this[field]);
this[field].remove();
this[field] = null
}
},

View File

@ -70,10 +70,10 @@ browser.jar:
skin/classic/browser/urlbar-arrow.png
skin/classic/browser/webRTC-shareDevice-16.png
skin/classic/browser/webRTC-shareDevice-64.png
skin/classic/browser/webRTC-sharingDevice-16.png
skin/classic/browser/webRTC-sharingDevice-16.png (../shared/webrtc/webRTC-sharingDevice-16.png)
skin/classic/browser/webRTC-shareMicrophone-16.png
skin/classic/browser/webRTC-shareMicrophone-64.png
skin/classic/browser/webRTC-sharingMicrophone-16.png
skin/classic/browser/webRTC-sharingMicrophone-16.png (../shared/webrtc/webRTC-sharingMicrophone-16.png)
skin/classic/browser/webRTC-shareScreen-16.png (../shared/webrtc/webRTC-shareScreen-16.png)
skin/classic/browser/webRTC-shareScreen-64.png (../shared/webrtc/webRTC-shareScreen-64.png)
skin/classic/browser/webRTC-sharingScreen-16.png (../shared/webrtc/webRTC-sharingScreen-16.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -117,23 +117,27 @@ browser.jar:
skin/classic/browser/webRTC-shareDevice-16@2x.png
skin/classic/browser/webRTC-shareDevice-64.png
skin/classic/browser/webRTC-shareDevice-64@2x.png
skin/classic/browser/webRTC-sharingDevice-16.png
skin/classic/browser/webRTC-sharingDevice-16@2x.png
skin/classic/browser/webRTC-sharingDevice-16.png (../shared/webrtc/webRTC-sharingDevice-16.png)
skin/classic/browser/webRTC-sharingDevice-16@2x.png (../shared/webrtc/webRTC-sharingDevice-16@2x.png)
skin/classic/browser/webRTC-shareMicrophone-16.png
skin/classic/browser/webRTC-shareMicrophone-16@2x.png
skin/classic/browser/webRTC-shareMicrophone-64.png
skin/classic/browser/webRTC-shareMicrophone-64@2x.png
skin/classic/browser/webRTC-sharingMicrophone-16.png
skin/classic/browser/webRTC-sharingMicrophone-16@2x.png
skin/classic/browser/webRTC-sharingMicrophone-16.png (../shared/webrtc/webRTC-sharingMicrophone-16.png)
skin/classic/browser/webRTC-sharingMicrophone-16@2x.png (../shared/webrtc/webRTC-sharingMicrophone-16@2x.png)
skin/classic/browser/webRTC-shareScreen-16.png (../shared/webrtc/webRTC-shareScreen-16.png)
skin/classic/browser/webRTC-shareScreen-16@2x.png (../shared/webrtc/webRTC-shareScreen-16@2x.png)
skin/classic/browser/webRTC-shareScreen-64.png (../shared/webrtc/webRTC-shareScreen-64.png)
skin/classic/browser/webRTC-shareScreen-64@2x.png (../shared/webrtc/webRTC-shareScreen-64@2x.png)
skin/classic/browser/webRTC-sharingScreen-16.png (../shared/webrtc/webRTC-sharingScreen-16.png)
skin/classic/browser/webRTC-sharingScreen-16@2x.png (../shared/webrtc/webRTC-sharingScreen-16@2x.png)
skin/classic/browser/webRTC-camera-black-16.png
skin/classic/browser/webRTC-microphone-black-16.png
skin/classic/browser/webRTC-screen-black-16.png
skin/classic/browser/webRTC-sharingDevice-menubar.png
skin/classic/browser/webRTC-sharingDevice-menubar@2x.png
skin/classic/browser/webRTC-sharingMicrophone-menubar.png
skin/classic/browser/webRTC-sharingMicrophone-menubar@2x.png
skin/classic/browser/webRTC-sharingScreen-menubar.png
skin/classic/browser/webRTC-sharingScreen-menubar@2x.png
skin/classic/browser/webRTC-indicator.css
skin/classic/browser/loop/toolbar.png (loop/toolbar.png)
skin/classic/browser/loop/toolbar@2x.png (loop/toolbar@2x.png)
skin/classic/browser/loop/toolbar-inverted.png (loop/toolbar-inverted.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,35 @@
/* 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/. */
#webRTC-sharingCamera-menu {
list-style-image: url("chrome://browser/skin/webRTC-sharingDevice-menubar.png");
}
#webRTC-sharingMicrophone-menu {
list-style-image: url("chrome://browser/skin/webRTC-sharingMicrophone-menubar.png");
}
#webRTC-sharingScreen-menu {
list-style-image: url("chrome://browser/skin/webRTC-sharingScreen-menubar.png");
}
@media (min-resolution: 2dppx) {
#webRTC-sharingCamera-menu {
list-style-image: url("chrome://browser/skin/webRTC-sharingDevice-menubar@2x.png");
}
#webRTC-sharingMicrophone-menu {
list-style-image: url("chrome://browser/skin/webRTC-sharingMicrophone-menubar@2x.png");
}
#webRTC-sharingScreen-menu {
list-style-image: url("chrome://browser/skin/webRTC-sharingScreen-menubar@2x.png");
}
}
#webRTC-sharingCamera-menu > menupopup,
#webRTC-sharingMicrophone-menu > menupopup,
#webRTC-sharingScreen-menu > menupopup {
list-style-image: none; /* don't inherit into menu items */
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 716 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -109,3 +109,8 @@ window[sharingscreen][sharingvideo] > #shareSeparator,
window[sharingscreen][sharingaudio] > #shareSeparator {
display: -moz-box;
}
:-moz-any(#audioVideoButton, #screenShareButton,
#firefoxButton):-moz-focusring > .button-box {
border: none;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -91,10 +91,10 @@ browser.jar:
skin/classic/browser/notification-pluginBlocked.png (../shared/plugins/notification-pluginBlocked.png)
skin/classic/browser/webRTC-shareDevice-16.png
skin/classic/browser/webRTC-shareDevice-64.png
skin/classic/browser/webRTC-sharingDevice-16.png
skin/classic/browser/webRTC-sharingDevice-16.png (../shared/webrtc/webRTC-sharingDevice-16.png)
skin/classic/browser/webRTC-shareMicrophone-16.png
skin/classic/browser/webRTC-shareMicrophone-64.png
skin/classic/browser/webRTC-sharingMicrophone-16.png
skin/classic/browser/webRTC-sharingMicrophone-16.png (../shared/webrtc/webRTC-sharingMicrophone-16.png)
skin/classic/browser/webRTC-shareScreen-16.png (../shared/webrtc/webRTC-shareScreen-16.png)
skin/classic/browser/webRTC-shareScreen-64.png (../shared/webrtc/webRTC-shareScreen-64.png)
skin/classic/browser/webRTC-sharingScreen-16.png (../shared/webrtc/webRTC-sharingScreen-16.png)
@ -510,10 +510,10 @@ browser.jar:
skin/classic/aero/browser/notification-pluginBlocked.png (../shared/plugins/notification-pluginBlocked.png)
skin/classic/aero/browser/webRTC-shareDevice-16.png
skin/classic/aero/browser/webRTC-shareDevice-64.png
skin/classic/aero/browser/webRTC-sharingDevice-16.png
skin/classic/aero/browser/webRTC-sharingDevice-16.png (../shared/webrtc/webRTC-sharingDevice-16.png)
skin/classic/aero/browser/webRTC-shareMicrophone-16.png
skin/classic/aero/browser/webRTC-shareMicrophone-64.png
skin/classic/aero/browser/webRTC-sharingMicrophone-16.png
skin/classic/aero/browser/webRTC-sharingMicrophone-16.png (../shared/webrtc/webRTC-sharingMicrophone-16.png)
skin/classic/aero/browser/webRTC-shareScreen-16.png (../shared/webrtc/webRTC-shareScreen-16.png)
skin/classic/aero/browser/webRTC-shareScreen-64.png (../shared/webrtc/webRTC-shareScreen-64.png)
skin/classic/aero/browser/webRTC-sharingScreen-16.png (../shared/webrtc/webRTC-sharingScreen-16.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -10,9 +10,21 @@ const Cc = Components.classes;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
const kEntities = { "geolocation": "geolocation",
"desktop-notification": "desktopNotification",
"contacts": "contacts" };
const kEntities = {
"contacts": "contacts",
"desktop-notification": "desktopNotification",
"device-storage:music": "deviceStorageMusic",
"device-storage:pictures": "deviceStoragePictures",
"device-storage:sdcard": "deviceStorageSdcard",
"device-storage:videos": "deviceStorageVideos",
"geolocation": "geolocation",
};
// For these types, prompt for permission if action is unknown.
const PROMPT_FOR_UNKNOWN = [
"desktop-notification",
"geolocation",
];
function ContentPermissionPrompt() {}
@ -21,18 +33,19 @@ ContentPermissionPrompt.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]),
handleExistingPermission: function handleExistingPermission(request, type, isApp) {
handleExistingPermission: function handleExistingPermission(request, type, denyUnknown) {
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, type);
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
request.allow();
return true;
}
if (result == Ci.nsIPermissionManager.DENY_ACTION) {
request.cancel();
return true;
}
if (isApp && (result == Ci.nsIPermissionManager.UNKNOWN_ACTION && !!kEntities[type])) {
if (denyUnknown && result == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
request.cancel();
return true;
}
@ -71,7 +84,10 @@ ContentPermissionPrompt.prototype = {
let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
// Returns true if the request was handled
if (this.handleExistingPermission(request, perm.type, isApp))
let access = (perm.access && perm.access !== "unused") ?
(perm.type + "-" + perm.access) : perm.type;
if (this.handleExistingPermission(request, access,
/* denyUnknown */ isApp || PROMPT_FOR_UNKNOWN.indexOf(perm.type) < 0))
return;
let chromeWin = this.getChromeForRequest(request);

View File

@ -116,6 +116,35 @@ contacts.ask=Allow %S to access your contacts?
# checkbox to indicate whether or not the user wants to make a permanent decision.
contacts.dontAskAgain=Don't ask again for this site
# Device Storage API
deviceStorageMusic.allow=Allow
deviceStorageMusic.dontAllow=Don't allow
deviceStorageMusic.ask=Allow %S access to your music?
# LOCALIZATION NOTE (deviceStorageMusic.dontAskAgain): This label appears next to a
# checkbox to indicate whether or not the user wants to make a permanent decision.
deviceStorageMusic.dontAskAgain=Don't ask again for this site
deviceStoragePictures.allow=Allow
deviceStoragePictures.dontAllow=Don't allow
deviceStoragePictures.ask=Allow %S access to your images?
# LOCALIZATION NOTE (deviceStoragePictures.dontAskAgain): This label appears next to a
# checkbox to indicate whether or not the user wants to make a permanent decision.
deviceStoragePictures.dontAskAgain=Don't ask again for this site
deviceStorageSdcard.allow=Allow
deviceStorageSdcard.dontAllow=Don't allow
deviceStorageSdcard.ask=Allow %S access to external storage?
# LOCALIZATION NOTE (deviceStorageSdcard.dontAskAgain): This label appears next to a
# checkbox to indicate whether or not the user wants to make a permanent decision.
deviceStorageSdcard.dontAskAgain=Don't ask again for this site
deviceStorageVideos.allow=Allow
deviceStorageVideos.dontAllow=Don't allow
deviceStorageVideos.ask=Allow %S access to your videos?
# LOCALIZATION NOTE (deviceStorageVideos.dontAskAgain): This label appears next to a
# checkbox to indicate whether or not the user wants to make a permanent decision.
deviceStorageVideos.dontAskAgain=Don't ask again for this site
# New Tab Popup
# LOCALIZATION NOTE (newtabpopup, newprivatetabpopup): Semicolon-separated list of plural forms.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals

View File

@ -739,6 +739,12 @@ Database::InitSchema(bool* aDatabaseMigrated)
// Firefox 24 uses schema version 23.
if (currentSchemaVersion < 24) {
rv = MigrateV24Up();
NS_ENSURE_SUCCESS(rv, rv);
}
// Firefox 34 uses schema version 24.
// Schema Upgrades must add migration code here.
rv = UpdateBookmarkRootTitles();
@ -961,6 +967,13 @@ Database::InitTempTriggers()
rv = mMainConn->ExecuteSimpleSQL(CREATE_PLACES_AFTERUPDATE_TYPED_TRIGGER);
NS_ENSURE_SUCCESS(rv, rv);
rv = mMainConn->ExecuteSimpleSQL(CREATE_FOREIGNCOUNT_AFTERDELETE_TRIGGER);
NS_ENSURE_SUCCESS(rv, rv);
rv = mMainConn->ExecuteSimpleSQL(CREATE_FOREIGNCOUNT_AFTERINSERT_TRIGGER);
NS_ENSURE_SUCCESS(rv, rv);
rv = mMainConn->ExecuteSimpleSQL(CREATE_FOREIGNCOUNT_AFTERUPDATE_TRIGGER);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
@ -1915,6 +1928,36 @@ Database::MigrateV23Up()
return NS_OK;
}
nsresult
Database::MigrateV24Up()
{
MOZ_ASSERT(NS_IsMainThread());
// Add a foreign_count column to moz_places
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT foreign_count FROM moz_places"
), getter_AddRefs(stmt));
if (NS_FAILED(rv)) {
rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_places ADD COLUMN foreign_count INTEGER DEFAULT 0 NOT NULL"));
NS_ENSURE_SUCCESS(rv, rv);
}
// Adjust counts for all the rows
nsCOMPtr<mozIStorageStatement> updateStmt;
rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
"UPDATE moz_places SET foreign_count = "
"(SELECT count(*) FROM moz_bookmarks WHERE fk = moz_places.id) "
), getter_AddRefs(updateStmt));
NS_ENSURE_SUCCESS(rv, rv);
mozStorageStatementScoper updateScoper(updateStmt);
rv = updateStmt->Execute();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
void
Database::Shutdown()
{

View File

@ -16,7 +16,7 @@
// This is the schema version. Update it at any schema change and add a
// corresponding migrateVxx method below.
#define DATABASE_SCHEMA_VERSION 23
#define DATABASE_SCHEMA_VERSION 24
// Fired after Places inited.
#define TOPIC_PLACES_INIT_COMPLETE "places-init-complete"
@ -276,6 +276,7 @@ protected:
nsresult MigrateV21Up();
nsresult MigrateV22Up();
nsresult MigrateV23Up();
nsresult MigrateV24Up();
nsresult UpdateBookmarkRootTitles();
nsresult CheckAndUpdateGUIDs();

View File

@ -682,6 +682,12 @@ this.PlacesDBUtils = {
")");
cleanupStatements.push(fixRedirectsHidden);
// L.4 recalculate foreign_count.
let fixForeignCount = DBConn.createAsyncStatement(
"UPDATE moz_places SET foreign_count = " +
"(SELECT count(*) FROM moz_bookmarks WHERE fk = moz_places.id )");
cleanupStatements.push(fixForeignCount);
// MAINTENANCE STATEMENTS SHOULD GO ABOVE THIS POINT!
return cleanupStatements;

View File

@ -0,0 +1,160 @@
/* 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/. */
/*
* Provides functions to handle search engine URLs in the browser history.
*/
"use strict";
this.EXPORTED_SYMBOLS = [ "PlacesSearchAutocompleteProvider" ];
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const SEARCH_ENGINE_TOPIC = "browser-search-engine-modified";
const SearchAutocompleteProviderInternal = {
/**
* Array of objects in the format returned by findMatchByToken.
*/
priorityMatches: null,
initialize: function () {
return new Promise((resolve, reject) => {
Services.search.init(status => {
if (!Components.isSuccessCode(status)) {
reject(new Error("Unable to initialize search service."));
}
try {
// The initial loading of the search engines must succeed.
this._refresh();
Services.obs.addObserver(this, SEARCH_ENGINE_TOPIC, true);
this.initialized = true;
resolve();
} catch (ex) {
reject(ex);
}
});
});
},
initialized: false,
observe: function (subject, topic, data) {
switch (data) {
case "engine-added":
case "engine-changed":
case "engine-removed":
this._refresh();
}
},
_refresh: function () {
this.priorityMatches = [];
// The search engines will always be processed in the order returned by the
// search service, which can be defined by the user.
Services.search.getVisibleEngines().forEach(e => this._addEngine(e));
},
_addEngine: function (engine) {
let token = engine.getResultDomain();
if (!token) {
return;
}
this.priorityMatches.push({
token: token,
// The searchForm property returns a simple URL for the search engine, but
// we may need an URL which includes an affiliate code (bug 990799).
url: engine.searchForm,
engineName: engine.name,
iconUrl: engine.iconURI ? engine.iconURI.spec : null,
});
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
}
let gInitializationPromise = null;
this.PlacesSearchAutocompleteProvider = Object.freeze({
/**
* Starts initializing the component and returns a promise that is resolved or
* rejected when initialization finished. The same promise is returned if
* this function is called multiple times.
*/
ensureInitialized: function () {
if (!gInitializationPromise) {
gInitializationPromise = SearchAutocompleteProviderInternal.initialize();
}
return gInitializationPromise;
},
/**
* Matches a given string to an item that should be included by URL search
* components, like autocomplete in the address bar.
*
* @param searchToken
* String containing the first part of the matching domain name.
*
* @return An object with the following properties, or undefined if the token
* does not match any relevant URL:
* {
* token: The full string used to match the search term to the URL.
* url: The URL to navigate to if the match is selected.
* engineName: The display name of the search engine.
* iconUrl: Icon associated to the match, or null if not available.
* }
*/
findMatchByToken: Task.async(function* (searchToken) {
yield this.ensureInitialized();
// Match at the beginning for now. In the future, an "options" argument may
// allow the matching behavior to be tuned.
return SearchAutocompleteProviderInternal.priorityMatches
.find(m => m.token.startsWith(searchToken));
}),
/**
* Synchronously determines if the provided URL represents results from a
* search engine, and provides details about the match.
*
* @param url
* String containing the URL to parse.
*
* @return An object with the following properties, or null if the URL does
* not represent a search result:
* {
* engineName: The display name of the search engine.
* terms: The originally sought terms extracted from the URI.
* }
*
* @remarks The asynchronous ensureInitialized function must be called before
* this synchronous method can be used.
*
* @note This API function needs to be synchronous because it is called inside
* a row processing callback of Sqlite.jsm, in UnifiedComplete.js.
*/
parseSubmissionURL: function (url) {
if (!SearchAutocompleteProviderInternal.initialized) {
throw new Error("The component has not been initialized.");
}
let parseUrlResult = Services.search.parseSubmissionURL(url);
return parseUrlResult.engine && {
engineName: parseUrlResult.engine.name,
terms: parseUrlResult.terms,
};
},
});

View File

@ -1,142 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = [ "PriorityUrlProvider" ];
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Task.jsm");
/**
* Provides search engines matches to the PriorityUrlProvider through the
* search engines definitions handled by the Search Service.
*/
const SEARCH_ENGINE_TOPIC = "browser-search-engine-modified";
let SearchEnginesProvider = {
init: function () {
this._engines = new Map();
let deferred = Promise.defer();
Services.search.init(rv => {
if (Components.isSuccessCode(rv)) {
Services.search.getVisibleEngines().forEach(this._addEngine, this);
deferred.resolve();
} else {
deferred.reject(new Error("Unable to initialize search service."));
}
});
Services.obs.addObserver(this, SEARCH_ENGINE_TOPIC, true);
return deferred.promise;
},
observe: function (engine, topic, verb) {
let engine = engine.QueryInterface(Ci.nsISearchEngine);
switch (verb) {
case "engine-added":
this._addEngine(engine);
break;
case "engine-changed":
if (engine.hidden) {
this._removeEngine(engine);
} else {
this._addEngine(engine);
}
break;
case "engine-removed":
this._removeEngine(engine);
break;
}
},
_addEngine: function (engine) {
if (this._engines.has(engine.name)) {
return;
}
let token = engine.getResultDomain();
if (!token) {
return;
}
let match = { token: token,
// TODO (bug 990799): searchForm should provide an usable
// url with affiliate code, if available.
url: engine.searchForm,
title: engine.name,
iconUrl: engine.iconURI ? engine.iconURI.spec : null,
reason: "search" }
this._engines.set(engine.name, match);
PriorityUrlProvider.addMatch(match);
},
_removeEngine: function (engine) {
if (!this._engines.has(engine.name)) {
return;
}
this._engines.delete(engine.name);
PriorityUrlProvider.removeMatchByToken(engine.getResultDomain());
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference])
}
/**
* The PriorityUrlProvider allows to match a given string to a list of
* urls that should have priority in url search components, like autocomplete.
* Each returned match is an object with the following properties:
* - token: string used to match the search term to the url
* - url: url string represented by the match
* - title: title describing the match, or an empty string if not available
* - iconUrl: url of the icon associated to the match, or null if not available
* - reason: a string describing the origin of the match, for example if it
* represents a search engine, it will be "search".
*/
let matches = new Map();
let initialized = false;
function promiseInitialized() {
if (initialized) {
return Promise.resolve();
}
return Task.spawn(function* () {
try {
yield SearchEnginesProvider.init();
} catch (ex) {
Cu.reportError(ex);
}
initialized = true;
});
}
this.PriorityUrlProvider = Object.freeze({
addMatch: function (match) {
matches.set(match.token, match);
},
removeMatchByToken: function (token) {
matches.delete(token);
},
getMatch: function (searchToken) {
return Task.spawn(function* () {
yield promiseInitialized();
for (let [token, match] of matches.entries()) {
// Match at the beginning for now. In future an aOptions argument may
// allow to control the matching behavior.
if (token.startsWith(searchToken)) {
return match;
}
}
return null;
}.bind(this));
}
});

View File

@ -22,25 +22,25 @@ const DEFAULT_BEHAVIOR = 0;
const PREF_BRANCH = "browser.urlbar.";
// Prefs are defined as [pref name, default value].
const PREF_ENABLED = [ "autocomplete.enabled", true ];
const PREF_AUTOFILL = [ "autoFill", true ];
const PREF_AUTOFILL_TYPED = [ "autoFill.typed", true ];
const PREF_AUTOFILL_PRIORITY = [ "autoFill.priority", true ];
const PREF_DELAY = [ "delay", 50 ];
const PREF_BEHAVIOR = [ "matchBehavior", MATCH_BOUNDARY_ANYWHERE ];
const PREF_DEFAULT_BEHAVIOR = [ "default.behavior", DEFAULT_BEHAVIOR ];
const PREF_EMPTY_BEHAVIOR = [ "default.behavior.emptyRestriction",
Ci.mozIPlacesAutoComplete.BEHAVIOR_HISTORY |
Ci.mozIPlacesAutoComplete.BEHAVIOR_TYPED ];
const PREF_FILTER_JS = [ "filter.javascript", true ];
const PREF_MAXRESULTS = [ "maxRichResults", 25 ];
const PREF_RESTRICT_HISTORY = [ "restrict.history", "^" ];
const PREF_RESTRICT_BOOKMARKS = [ "restrict.bookmark", "*" ];
const PREF_RESTRICT_TYPED = [ "restrict.typed", "~" ];
const PREF_RESTRICT_TAG = [ "restrict.tag", "+" ];
const PREF_RESTRICT_SWITCHTAB = [ "restrict.openpage", "%" ];
const PREF_MATCH_TITLE = [ "match.title", "#" ];
const PREF_MATCH_URL = [ "match.url", "@" ];
const PREF_ENABLED = [ "autocomplete.enabled", true ];
const PREF_AUTOFILL = [ "autoFill", true ];
const PREF_AUTOFILL_TYPED = [ "autoFill.typed", true ];
const PREF_AUTOFILL_SEARCHENGINES = [ "autoFill.searchEngines", true ];
const PREF_DELAY = [ "delay", 50 ];
const PREF_BEHAVIOR = [ "matchBehavior", MATCH_BOUNDARY_ANYWHERE ];
const PREF_DEFAULT_BEHAVIOR = [ "default.behavior", DEFAULT_BEHAVIOR ];
const PREF_EMPTY_BEHAVIOR = [ "default.behavior.emptyRestriction",
Ci.mozIPlacesAutoComplete.BEHAVIOR_HISTORY |
Ci.mozIPlacesAutoComplete.BEHAVIOR_TYPED ];
const PREF_FILTER_JS = [ "filter.javascript", true ];
const PREF_MAXRESULTS = [ "maxRichResults", 25 ];
const PREF_RESTRICT_HISTORY = [ "restrict.history", "^" ];
const PREF_RESTRICT_BOOKMARKS = [ "restrict.bookmark", "*" ];
const PREF_RESTRICT_TYPED = [ "restrict.typed", "~" ];
const PREF_RESTRICT_TAG = [ "restrict.tag", "+" ];
const PREF_RESTRICT_SWITCHTAB = [ "restrict.openpage", "%" ];
const PREF_MATCH_TITLE = [ "match.title", "#" ];
const PREF_MATCH_URL = [ "match.url", "@" ];
// Match type constants.
// These indicate what type of search function we should be using.
@ -62,11 +62,14 @@ const QUERYTYPE_AUTOFILL_URL = 3;
// "comment" back into the title and the tag.
const TITLE_TAGS_SEPARATOR = " \u2013 ";
// This separator identifies the search engine name in the title.
const TITLE_SEARCH_ENGINE_SEPARATOR = " \u00B7\u2013\u00B7 ";
// Telemetry probes.
const TELEMETRY_1ST_RESULT = "PLACES_AUTOCOMPLETE_1ST_RESULT_TIME_MS";
// The default frecency value used when inserting priority results.
const FRECENCY_PRIORITY_DEFAULT = 1000;
// The default frecency value used when inserting search engine results.
const FRECENCY_SEARCHENGINES_DEFAULT = 1000;
// Sqlite result row index constants.
const QUERYINDEX_QUERYTYPE = 0;
@ -198,10 +201,30 @@ const SQL_HOST_QUERY = sql(
const SQL_TYPED_HOST_QUERY = SQL_HOST_QUERY.replace("/*CONDITIONS*/",
"AND typed = 1");
const SQL_BOOKMARKED_HOST_QUERY = sql(
"/* do not warn (bug NA): not worth to index on (typed, frecency) */",
"SELECT :query_type, host || '/', IFNULL(prefix, '') || host || '/',",
"NULL, (",
"SELECT foreign_count > 0 FROM moz_places ",
"WHERE rev_host = get_unreversed_host(host || '.') || '.'",
"OR rev_host = get_unreversed_host(host || '.') || '.www.'",
") AS bookmarked, NULL, NULL, NULL, NULL, NULL, NULL, frecency",
"FROM moz_hosts",
"WHERE host BETWEEN :searchString AND :searchString || X'FFFF'",
"AND bookmarked",
"AND frecency <> 0",
"/*CONDITIONS*/",
"ORDER BY frecency DESC",
"LIMIT 1");
const SQL_BOOKMARKED_TYPED_HOST_QUERY =
SQL_BOOKMARKED_HOST_QUERY.replace("/*CONDITIONS*/", "AND typed = 1");
const SQL_URL_QUERY = sql(
"/* do not warn (bug no): cannot use an index */",
"SELECT :query_type, h.url, NULL,",
"NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, h.frecency",
"NULL, foreign_count > 0 AS bookmarked, NULL, NULL, NULL, NULL, NULL, NULL, h.frecency",
"FROM moz_places h",
"WHERE h.frecency <> 0",
"/*CONDITIONS*/",
@ -215,6 +238,13 @@ const SQL_URL_QUERY = sql(
const SQL_TYPED_URL_QUERY = SQL_URL_QUERY.replace("/*CONDITIONS*/",
"AND typed = 1");
// TODO (bug 1045924): use foreign_count once available.
const SQL_BOOKMARKED_URL_QUERY =
SQL_URL_QUERY.replace("/*CONDITIONS*/", "AND bookmarked");
const SQL_BOOKMARKED_TYPED_URL_QUERY =
SQL_URL_QUERY.replace("/*CONDITIONS*/", "AND bookmarked AND typed = 1");
////////////////////////////////////////////////////////////////////////////////
//// Getters
@ -237,8 +267,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PriorityUrlProvider",
"resource://gre/modules/PriorityUrlProvider.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesSearchAutocompleteProvider",
"resource://gre/modules/PlacesSearchAutocompleteProvider.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "textURIService",
"@mozilla.org/intl/texttosuburi;1",
@ -332,7 +362,7 @@ XPCOMUtils.defineLazyGetter(this, "Prefs", () => {
store.enabled = prefs.get(...PREF_ENABLED);
store.autofill = prefs.get(...PREF_AUTOFILL);
store.autofillTyped = prefs.get(...PREF_AUTOFILL_TYPED);
store.autofillPriority = prefs.get(...PREF_AUTOFILL_PRIORITY);
store.autofillSearchEngines = prefs.get(...PREF_AUTOFILL_SEARCHENGINES);
store.delay = prefs.get(...PREF_DELAY);
store.matchBehavior = prefs.get(...PREF_BEHAVIOR);
store.filterJavaScript = prefs.get(...PREF_FILTER_JS);
@ -602,8 +632,12 @@ Search.prototype = {
this._pendingQuery = true;
TelemetryStopwatch.start(TELEMETRY_1ST_RESULT);
// Since we call the synchronous parseSubmissionURL function later, we must
// wait for the initialization of PlacesSearchAutocompleteProvider first.
yield PlacesSearchAutocompleteProvider.ensureInitialized();
// For any given search, we run many queries:
// 1) priority domains
// 1) search engine domains
// 2) inline completion
// 3) keywords (this._keywordQuery)
// 4) adaptive learning (this._adaptiveQuery)
@ -622,7 +656,7 @@ Search.prototype = {
PlacesUtils.bookmarks.getURIForKeyword(this._searchTokens[0])) {
queries.unshift(this._keywordQuery);
} else if (this._searchTokens.length == 1) {
yield this._matchPriorityUrl();
yield this._matchSearchEngineUrl();
}
if (this._shouldAutofill) {
@ -673,19 +707,21 @@ Search.prototype = {
}
}),
_matchPriorityUrl: function* () {
if (!Prefs.autofillPriority)
_matchSearchEngineUrl: function* () {
if (!Prefs.autofillSearchEngines)
return;
let priorityMatch = yield PriorityUrlProvider.getMatch(this._searchString);
if (priorityMatch) {
let match = yield PlacesSearchAutocompleteProvider.findMatchByToken(
this._searchString);
if (match) {
this._result.setDefaultIndex(0);
this._addFrecencyMatch({
value: priorityMatch.token,
comment: priorityMatch.title,
icon: priorityMatch.iconUrl,
style: "priority-" + priorityMatch.reason,
finalCompleteValue: priorityMatch.url,
frecency: FRECENCY_PRIORITY_DEFAULT
value: match.token,
comment: match.engineName,
icon: match.iconUrl,
style: "priority-search",
finalCompleteValue: match.url,
frecency: FRECENCY_SEARCHENGINES_DEFAULT
});
}
},
@ -724,6 +760,30 @@ Search.prototype = {
this._frecencyMatches.sort((a, b) => a.frecency - b.frecency);
},
_maybeRestyleSearchMatch: function (match) {
// Return if the URL does not represent a search result.
let parseResult =
PlacesSearchAutocompleteProvider.parseSubmissionURL(match.value);
if (!parseResult) {
return;
}
// Do not apply the special style if the user is doing a search from the
// location bar but the entered terms match an irrelevant portion of the
// URL. For example, "https://www.google.com/search?q=terms&client=firefox"
// when searching for "Firefox".
let terms = parseResult.terms.toLowerCase();
if (this._searchTokens.length > 0 &&
this._searchTokens.every(token => terms.indexOf(token) == -1)) {
return;
}
// Use the special separator that the binding will use to style the item.
match.style = "search " + match.style;
match.comment = parseResult.terms + TITLE_SEARCH_ENGINE_SEPARATOR +
parseResult.engineName;
},
_addMatch: function (match) {
let notifyResults = false;
@ -749,10 +809,19 @@ Search.prototype = {
this._usedPlaceIds.add(match.placeId);
this._usedURLs.add(urlMapKey);
if (!match.style) {
match.style = "favicon";
}
// Restyle past searches, unless they are bookmarks or special results.
if (match.style == "favicon") {
this._maybeRestyleSearchMatch(match);
}
this._result.appendMatch(match.value,
match.comment,
match.icon || PlacesUtils.favicons.defaultFavicon.spec,
match.style || "favicon",
match.style,
match.finalCompleteValue);
notifyResults = true;
}
@ -784,7 +853,8 @@ Search.prototype = {
}
match.value = this._strippedPrefix + trimmedHost;
match.comment = trimmedHost;
// Remove the trailing slash.
match.comment = stripHttpAndTrim(trimmedHost);
match.finalCompleteValue = untrimmedHost;
match.frecency = frecency;
return match;
@ -1020,8 +1090,18 @@ Search.prototype = {
// Then, we should not try to autofill if the behavior is not the default.
// TODO (bug 751709): Ideally we should have a more fine-grained behavior
// here, but for now it's enough to just check for default behavior.
if (Prefs.defaultBehavior != DEFAULT_BEHAVIOR)
return false;
if (Prefs.defaultBehavior != DEFAULT_BEHAVIOR) {
// autoFill can only cope with history or bookmarks entries
// (typed or not).
if (!this.hasBehavior("typed") &&
!this.hasBehavior("history") &&
!this.hasBehavior("bookmark"))
return false;
// autoFill doesn't search titles or tags.
if (this.hasBehavior("title") || this.hasBehavior("tags"))
return false;
}
// Don't try to autofill if the search term includes any whitespace.
// This may confuse completeDefaultIndex cause the AUTOCOMPLETE_MATCH
@ -1049,13 +1129,21 @@ Search.prototype = {
* @return an array consisting of the correctly optimized query to search the
* database with and an object containing the params to bound.
*/
get _hostQuery() [
Prefs.autofillTyped ? SQL_TYPED_HOST_QUERY : SQL_HOST_QUERY,
{
query_type: QUERYTYPE_AUTOFILL_HOST,
searchString: this._searchString.toLowerCase()
}
],
get _hostQuery() {
let typed = Prefs.autofillTyped || this.hasBehavior("typed");
let bookmarked = this.hasBehavior("bookmark");
return [
bookmarked ? typed ? SQL_BOOKMARKED_TYPED_HOST_QUERY
: SQL_BOOKMARKED_HOST_QUERY
: typed ? SQL_TYPED_HOST_QUERY
: SQL_HOST_QUERY,
{
query_type: QUERYTYPE_AUTOFILL_HOST,
searchString: this._searchString.toLowerCase()
}
];
},
/**
* Obtains the query to search for autoFill url results.
@ -1063,15 +1151,23 @@ Search.prototype = {
* @return an array consisting of the correctly optimized query to search the
* database with and an object containing the params to bound.
*/
get _urlQuery() [
Prefs.autofillTyped ? SQL_TYPED_URL_QUERY : SQL_URL_QUERY,
{
query_type: QUERYTYPE_AUTOFILL_URL,
searchString: this._autofillUrlSearchString,
matchBehavior: MATCH_BEGINNING_CASE_SENSITIVE,
searchBehavior: Ci.mozIPlacesAutoComplete.BEHAVIOR_URL
}
],
get _urlQuery() {
let typed = Prefs.autofillTyped || this.hasBehavior("typed");
let bookmarked = this.hasBehavior("bookmark");
return [
bookmarked ? typed ? SQL_BOOKMARKED_TYPED_URL_QUERY
: SQL_BOOKMARKED_URL_QUERY
: typed ? SQL_TYPED_URL_QUERY
: SQL_URL_QUERY,
{
query_type: QUERYTYPE_AUTOFILL_URL,
searchString: this._autofillUrlSearchString,
matchBehavior: MATCH_BEGINNING_CASE_SENSITIVE,
searchBehavior: Ci.mozIPlacesAutoComplete.BEHAVIOR_URL
}
];
},
/**
* Notifies the listener about results.

View File

@ -67,8 +67,8 @@ if CONFIG['MOZ_PLACES']:
'ColorConversion.js',
'PlacesBackups.jsm',
'PlacesDBUtils.jsm',
'PlacesSearchAutocompleteProvider.jsm',
'PlacesTransactions.jsm',
'PriorityUrlProvider.jsm'
]
EXTRA_PP_JS_MODULES += [

View File

@ -206,10 +206,9 @@ const EXPIRATION_QUERIES = {
+ "SELECT h.id, h.url, h.guid, h.last_visit_date, :limit_uris "
+ "FROM moz_places h "
+ "LEFT JOIN moz_historyvisits v ON h.id = v.place_id "
+ "LEFT JOIN moz_bookmarks b ON h.id = b.fk "
+ "WHERE h.last_visit_date IS NULL "
+ "AND h.foreign_count = 0 "
+ "AND v.id IS NULL "
+ "AND b.id IS NULL "
+ "AND frecency <> -1 "
+ "LIMIT :limit_uris",
actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.SHUTDOWN_DIRTY |
@ -231,10 +230,9 @@ const EXPIRATION_QUERIES = {
+ "SELECT h.id "
+ "FROM moz_places h "
+ "LEFT JOIN moz_historyvisits v ON h.id = v.place_id "
+ "LEFT JOIN moz_bookmarks b ON h.id = b.fk "
+ "WHERE h.last_visit_date IS NULL "
+ "AND h.foreign_count = 0 "
+ "AND v.id IS NULL "
+ "AND b.id IS NULL "
+ "LIMIT :limit_uris "
+ ")",
actions: ACTION.CLEAR_HISTORY

View File

@ -21,11 +21,9 @@
", frecency INTEGER DEFAULT -1 NOT NULL" \
", last_visit_date INTEGER " \
", guid TEXT" \
", foreign_count INTEGER DEFAULT 0 NOT NULL" \
")" \
)
#define MOZ_PLACES_COLUMNS \
"id, url, title, rev_host, visit_count, hidden, typed, favicon_id, " \
"frecency, last_visit_date"
#define CREATE_MOZ_HISTORYVISITS NS_LITERAL_CSTRING( \
"CREATE TABLE moz_historyvisits (" \
@ -37,8 +35,6 @@
", session INTEGER" \
")" \
)
#define MOZ_HISTORYVISITS_COLUMNS \
"id, from_visit, place_id, visit_date, visit_type, session"
#define CREATE_MOZ_INPUTHISTORY NS_LITERAL_CSTRING( \

View File

@ -175,4 +175,36 @@
"END" \
)
#define CREATE_FOREIGNCOUNT_AFTERDELETE_TRIGGER NS_LITERAL_CSTRING( \
"CREATE TEMP TRIGGER moz_bookmarks_foreign_count_afterdelete_trigger " \
"AFTER DELETE ON moz_bookmarks FOR EACH ROW " \
"BEGIN " \
"UPDATE moz_places " \
"SET foreign_count = foreign_count - 1 " \
"WHERE id = OLD.fk;" \
"END" \
)
#define CREATE_FOREIGNCOUNT_AFTERINSERT_TRIGGER NS_LITERAL_CSTRING( \
"CREATE TEMP TRIGGER moz_bookmarks_foreign_count_afterinsert_trigger " \
"AFTER INSERT ON moz_bookmarks FOR EACH ROW " \
"BEGIN " \
"UPDATE moz_places " \
"SET foreign_count = foreign_count + 1 " \
"WHERE id = NEW.fk;" \
"END" \
)
#define CREATE_FOREIGNCOUNT_AFTERUPDATE_TRIGGER NS_LITERAL_CSTRING( \
"CREATE TEMP TRIGGER moz_bookmarks_foreign_count_afterupdate_trigger " \
"AFTER UPDATE OF fk ON moz_bookmarks FOR EACH ROW " \
"BEGIN " \
"UPDATE moz_places " \
"SET foreign_count = foreign_count + 1 " \
"WHERE id = NEW.fk;" \
"UPDATE moz_places " \
"SET foreign_count = foreign_count - 1 " \
"WHERE id = OLD.fk;" \
"END" \
)
#endif // __nsPlacesTriggers_h__

View File

@ -0,0 +1,109 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
/* Bug 1017502 - Add a foreign_count column to moz_places
This tests, tests the triggers that adjust the foreign_count when a bookmark is
added or removed and also the maintenance task to fix wrong counts.
*/
const T_URI = NetUtil.newURI("https://www.mozilla.org/firefox/nightly/firstrun/");
function* getForeignCountForURL(conn, url){
let url = url instanceof Ci.nsIURI ? url.spec : url;
let rows = yield conn.executeCached(
"SELECT foreign_count FROM moz_places WHERE url = :t_url ", { t_url: url });
return rows[0].getResultByName("foreign_count");
}
function run_test() {
run_next_test();
}
add_task(function* add_remove_change_bookmark_test() {
let conn = yield PlacesUtils.promiseDBConnection();
// Simulate a visit to the url
yield promiseAddVisits(T_URI);
Assert.equal((yield getForeignCountForURL(conn, T_URI)), 0);
// Add 1st bookmark which should increment foreign_count by 1
let id1 = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
T_URI, PlacesUtils.bookmarks.DEFAULT_INDEX, "First Run");
Assert.equal((yield getForeignCountForURL(conn, T_URI)), 1);
// Add 2nd bookmark
let id2 = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.bookmarksMenuFolderId,
T_URI, PlacesUtils.bookmarks.DEFAULT_INDEX, "First Run");
Assert.equal((yield getForeignCountForURL(conn, T_URI)), 2);
// Remove 2nd bookmark which should decrement foreign_count by 1
PlacesUtils.bookmarks.removeItem(id2);
Assert.equal((yield getForeignCountForURL(conn, T_URI)), 1);
// Change first bookmark's URI
const URI2 = NetUtil.newURI("http://www.mozilla.org");
PlacesUtils.bookmarks.changeBookmarkURI(id1, URI2);
// Check foreign count for original URI
Assert.equal((yield getForeignCountForURL(conn, T_URI)), 0);
// Check foreign count for new URI
Assert.equal((yield getForeignCountForURL(conn, URI2)), 1);
// Cleanup - Remove changed bookmark
let id = PlacesUtils.bookmarks.getBookmarkIdsForURI(URI2);
PlacesUtils.bookmarks.removeItem(id);
Assert.equal((yield getForeignCountForURL(conn, URI2)), 0);
});
add_task(function* maintenance_foreign_count_test() {
let conn = yield PlacesUtils.promiseDBConnection();
// Simulate a visit to the url
yield promiseAddVisits(T_URI);
// Adjust the foreign_count for the added entry to an incorrect value
let deferred = Promise.defer();
let stmt = DBConn().createAsyncStatement(
"UPDATE moz_places SET foreign_count = 10 WHERE url = :t_url ");
stmt.params.t_url = T_URI.spec;
stmt.executeAsync({
handleCompletion: function(){
deferred.resolve();
}
});
stmt.finalize();
yield deferred.promise;
Assert.equal((yield getForeignCountForURL(conn, T_URI)), 10);
// Run maintenance
Components.utils.import("resource://gre/modules/PlacesDBUtils.jsm");
let promiseMaintenanceFinished =
promiseTopicObserved("places-maintenance-finished");
PlacesDBUtils.maintenanceOnIdle();
yield promiseMaintenanceFinished;
// Check if the foreign_count has been adjusted to the correct value
Assert.equal((yield getForeignCountForURL(conn, T_URI)), 0);
});
add_task(function* add_remove_tags_test(){
let conn = yield PlacesUtils.promiseDBConnection();
yield promiseAddVisits(T_URI);
Assert.equal((yield getForeignCountForURL(conn, T_URI)), 0);
// Check foreign count incremented by 1 for a single tag
PlacesUtils.tagging.tagURI(T_URI, ["test tag"]);
Assert.equal((yield getForeignCountForURL(conn, T_URI)), 1);
// Check foreign count is incremented by 2 for two tags
PlacesUtils.tagging.tagURI(T_URI, ["one", "two"]);
Assert.equal((yield getForeignCountForURL(conn, T_URI)), 3);
// Check foreign count is set to 0 when all tags are removed
PlacesUtils.tagging.untagURI(T_URI, ["test tag", "one", "two"]);
Assert.equal((yield getForeignCountForURL(conn, T_URI)), 0);
});

View File

@ -34,3 +34,4 @@ tail =
[test_992901-backup-unsorted-hierarchy.js]
[test_997030-bookmarks-html-encode.js]
[test_1016953-renaming-uncompressed.js]
[test_1017502-bookmarks_foreign_count.js]

View File

@ -3,7 +3,7 @@
* 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/. */
const CURRENT_SCHEMA_VERSION = 23;
const CURRENT_SCHEMA_VERSION = 24;
const NS_APP_USER_PROFILE_50_DIR = "ProfD";
const NS_APP_PROFILE_DIR_STARTUP = "ProfDS";

View File

@ -17,6 +17,8 @@ let (commonFile = do_get_file("../head_common.js", false)) {
// Put any other stuff relative to this test folder below.
const TITLE_SEARCH_ENGINE_SEPARATOR = " \u00B7\u2013\u00B7 ";
function run_test() {
run_next_test();
}
@ -147,9 +149,11 @@ function* check_autocomplete(test) {
if (matches[j] == undefined)
continue;
let { uri, title, tags } = matches[j];
let { uri, title, tags, searchEngine } = matches[j];
if (tags)
title += " \u2013 " + tags.sort().join(", ");
if (searchEngine)
title += TITLE_SEARCH_ENGINE_SEPARATOR + searchEngine;
do_log_info("Checking against expected '" + uri.spec + "', '" + title + "'...");
// Got a match on both uri and title?

View File

@ -0,0 +1,269 @@
/* 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/. */
/**
* Test autoFill for different default behaviors.
*/
add_task(function* test_default_behavior_host() {
let uri1 = NetUtil.newURI("http://typed/");
let uri2 = NetUtil.newURI("http://visited/");
let uri3 = NetUtil.newURI("http://bookmarked/");
let uri4 = NetUtil.newURI("http://tpbk/");
yield promiseAddVisits([
{ uri: uri1, title: "typed", transition: TRANSITION_TYPED },
{ uri: uri2, title: "visited" },
{ uri: uri4, title: "tpbk", transition: TRANSITION_TYPED },
]);
addBookmark( { uri: uri3, title: "bookmarked" } );
addBookmark( { uri: uri4, title: "tpbk" } );
// RESTRICT TO HISTORY.
Services.prefs.setIntPref("browser.urlbar.default.behavior", 1);
do_log_info("Restrict history, common visit, should not autoFill");
yield check_autocomplete({
search: "vi",
matches: [ { uri: uri2, title: "visited" } ],
autofilled: "vi",
completed: "vi"
});
do_log_info("Restrict history, typed visit, should autoFill");
yield check_autocomplete({
search: "ty",
matches: [ { uri: uri1, title: "typed" } ],
autofilled: "typed/",
completed: "typed/"
});
// Don't autoFill this one cause it's not typed.
do_log_info("Restrict history, bookmark, should not autoFill");
yield check_autocomplete({
search: "bo",
matches: [ ],
autofilled: "bo",
completed: "bo"
});
// Note we don't show this one cause it's not typed.
do_log_info("Restrict history, typed bookmark, should autoFill");
yield check_autocomplete({
search: "tp",
matches: [ { uri: uri4, title: "tpbk" } ],
autofilled: "tpbk/",
completed: "tpbk/"
});
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
// We are not restricting on typed, so we autoFill the bookmark even if we
// are restricted to history. We accept that cause not doing that
// would be a perf hit and the privacy implications are very weak.
do_log_info("Restrict history, bookmark, autoFill.typed = false, should autoFill");
yield check_autocomplete({
search: "bo",
matches: [ { uri: uri3, title: "bookmarked" } ],
autofilled: "bookmarked/",
completed: "bookmarked/"
});
do_log_info("Restrict history, common visit, autoFill.typed = false, should autoFill");
yield check_autocomplete({
search: "vi",
matches: [ { uri: uri2, title: "visited" } ],
autofilled: "visited/",
completed: "visited/"
});
// RESTRICT TO TYPED.
// This should basically ignore autoFill.typed and acts as if it would be set.
Services.prefs.setIntPref("browser.urlbar.default.behavior", 32);
// Typed behavior basically acts like history, but filters on typed.
do_log_info("Restrict typed, common visit, autoFill.typed = false, should not autoFill");
yield check_autocomplete({
search: "vi",
matches: [ ],
autofilled: "vi",
completed: "vi"
});
do_log_info("Restrict typed, typed visit, autofill.typed = false, should autoFill");
yield check_autocomplete({
search: "ty",
matches: [ { uri: uri1, title: "typed" } ],
autofilled: "typed/",
completed: "typed/"
});
do_log_info("Restrict typed, bookmark, autofill.typed = false, should not autoFill");
yield check_autocomplete({
search: "bo",
matches: [ ],
autofilled: "bo",
completed: "bo"
});
do_log_info("Restrict typed, typed bookmark, autofill.typed = false, should autoFill");
yield check_autocomplete({
search: "tp",
matches: [ { uri: uri4, title: "tpbk" } ],
autofilled: "tpbk/",
completed: "tpbk/"
});
// RESTRICT BOOKMARKS.
Services.prefs.setIntPref("browser.urlbar.default.behavior", 2);
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", true);
do_log_info("Restrict bookmarks, common visit, should not autoFill");
yield check_autocomplete({
search: "vi",
matches: [ ],
autofilled: "vi",
completed: "vi"
});
do_log_info("Restrict bookmarks, typed visit, should not autoFill");
yield check_autocomplete({
search: "ty",
matches: [ ],
autofilled: "ty",
completed: "ty"
});
// Don't autoFill this one cause it's not typed.
do_log_info("Restrict bookmarks, bookmark, should not autoFill");
yield check_autocomplete({
search: "bo",
matches: [ { uri: uri3, title: "bookmarked" } ],
autofilled: "bo",
completed: "bo"
});
// Note we don't show this one cause it's not typed.
do_log_info("Restrict bookmarks, typed bookmark, should autoFill");
yield check_autocomplete({
search: "tp",
matches: [ { uri: uri4, title: "tpbk" } ],
autofilled: "tpbk/",
completed: "tpbk/"
});
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
do_log_info("Restrict bookmarks, bookmark, autofill.typed = false, should autoFill");
yield check_autocomplete({
search: "bo",
matches: [ { uri: uri3, title: "bookmarked" } ],
autofilled: "bookmarked/",
completed: "bookmarked/"
});
yield cleanup();
});
add_task(function* test_default_behavior_url() {
let uri1 = NetUtil.newURI("http://typed/ty/");
let uri2 = NetUtil.newURI("http://visited/vi/");
let uri3 = NetUtil.newURI("http://bookmarked/bo/");
let uri4 = NetUtil.newURI("http://tpbk/tp/");
yield promiseAddVisits([
{ uri: uri1, title: "typed", transition: TRANSITION_TYPED },
{ uri: uri2, title: "visited" },
{ uri: uri4, title: "tpbk", transition: TRANSITION_TYPED },
]);
addBookmark( { uri: uri3, title: "bookmarked" } );
addBookmark( { uri: uri4, title: "tpbk" } );
// RESTRICT TO HISTORY.
Services.prefs.setIntPref("browser.urlbar.default.behavior", 1);
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", true);
do_log_info("URL: Restrict history, common visit, should not autoFill");
yield check_autocomplete({
search: "visited/v",
matches: [ { uri: uri2, title: "visited" } ],
autofilled: "visited/v",
completed: "visited/v"
});
do_log_info("URL: Restrict history, typed visit, should autoFill");
yield check_autocomplete({
search: "typed/t",
matches: [ { uri: uri1, title: "typed/ty/" } ],
autofilled: "typed/ty/",
completed: "http://typed/ty/"
});
// Don't autoFill this one cause it's not typed.
do_log_info("URL: Restrict history, bookmark, should not autoFill");
yield check_autocomplete({
search: "bookmarked/b",
matches: [ ],
autofilled: "bookmarked/b",
completed: "bookmarked/b"
});
// Note we don't show this one cause it's not typed.
do_log_info("URL: Restrict history, typed bookmark, should autoFill");
yield check_autocomplete({
search: "tpbk/t",
matches: [ { uri: uri4, title: "tpbk/tp/" } ],
autofilled: "tpbk/tp/",
completed: "http://tpbk/tp/"
});
// RESTRICT BOOKMARKS.
Services.prefs.setIntPref("browser.urlbar.default.behavior", 2);
do_log_info("URL: Restrict bookmarks, common visit, should not autoFill");
yield check_autocomplete({
search: "visited/v",
matches: [ ],
autofilled: "visited/v",
completed: "visited/v"
});
do_log_info("URL: Restrict bookmarks, typed visit, should not autoFill");
yield check_autocomplete({
search: "typed/t",
matches: [ ],
autofilled: "typed/t",
completed: "typed/t"
});
// Don't autoFill this one cause it's not typed.
do_log_info("URL: Restrict bookmarks, bookmark, should not autoFill");
yield check_autocomplete({
search: "bookmarked/b",
matches: [ { uri: uri3, title: "bookmarked" } ],
autofilled: "bookmarked/b",
completed: "bookmarked/b"
});
// Note we don't show this one cause it's not typed.
do_log_info("URL: Restrict bookmarks, typed bookmark, should autoFill");
yield check_autocomplete({
search: "tpbk/t",
matches: [ { uri: uri4, title: "tpbk/tp/" } ],
autofilled: "tpbk/tp/",
completed: "http://tpbk/tp/"
});
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
do_log_info("URL: Restrict bookmarks, bookmark, autofill.typed = false, should autoFill");
yield check_autocomplete({
search: "bookmarked/b",
matches: [ { uri: uri3, title: "bookmarked/bo/" } ],
autofilled: "bookmarked/bo/",
completed: "http://bookmarked/bo/"
});
yield cleanup();
});

View File

@ -12,7 +12,8 @@ add_task(function* test_dupe_urls() {
search: "moz",
autofilled: "mozilla.org/",
completed: "mozilla.org/",
matches: [ { uri: NetUtil.newURI("http://mozilla.org/"), title: "mozilla.org/" } ]
matches: [ { uri: NetUtil.newURI("http://mozilla.org/"),
title: "mozilla.org" } ]
});
yield cleanup();
});

View File

@ -0,0 +1,25 @@
/* 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/. */
add_task(function* test_searchEngine() {
Services.search.addEngineWithDetails("SearchEngine", "", "", "",
"GET", "http://s.example.com/search");
let engine = Services.search.getEngineByName("SearchEngine");
engine.addParam("q", "{searchTerms}", null);
do_register_cleanup(() => Services.search.removeEngine(engine));
let uri1 = NetUtil.newURI("http://s.example.com/search?q=Terms&client=1");
let uri2 = NetUtil.newURI("http://s.example.com/search?q=Terms&client=2");
yield promiseAddVisits({ uri: uri1, title: "Terms - SearchEngine Search" });
addBookmark({ uri: uri2, title: "Terms - SearchEngine Search" });
do_log_info("Past search terms should be styled, unless bookmarked");
yield check_autocomplete({
search: "term",
matches: [ { uri: uri1, title: "Terms", searchEngine: "SearchEngine" },
{ uri: uri2, title: "Terms - SearchEngine Search" } ]
});
yield cleanup();
});

View File

@ -358,6 +358,10 @@ add_task(function* test_special_searches() {
matches: [ { uri: uri11, title: "title", tags: [ "foo.bar" ] } ]
});
// Disable autoFill for the next tests, see test_autoFill_default_behavior.js
// for specific tests.
Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
// Test default usage by setting certain bits of default.behavior to 1
do_log_info("foo -> default history");
Services.prefs.setIntPref("browser.urlbar.default.behavior", 1);

View File

@ -9,6 +9,7 @@ tail =
[test_422277.js]
[test_autocomplete_functional.js]
[test_autocomplete_on_value_removed_479089.js]
[test_autoFill_default_behavior.js]
[test_casing.js]
[test_do_not_trim.js]
[test_download_embed_bookmarks.js]
@ -22,6 +23,7 @@ tail =
[test_match_beginning.js]
[test_multi_word_search.js]
[test_queryurl.js]
[test_searchEngine.js]
[test_special_search.js]
[test_swap_protocol.js]
[test_tabmatches.js]

View File

@ -2,7 +2,7 @@
* 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/. */
Cu.import("resource://gre/modules/PriorityUrlProvider.jsm");
Cu.import("resource://gre/modules/PlacesSearchAutocompleteProvider.jsm");
function run_test() {
run_next_test();
@ -11,15 +11,14 @@ function run_test() {
add_task(function* search_engine_match() {
let engine = yield promiseDefaultSearchEngine();
let token = engine.getResultDomain();
let match = yield PriorityUrlProvider.getMatch(token.substr(0, 1));
let match = yield PlacesSearchAutocompleteProvider.findMatchByToken(token.substr(0, 1));
do_check_eq(match.url, engine.searchForm);
do_check_eq(match.title, engine.name);
do_check_eq(match.engineName, engine.name);
do_check_eq(match.iconUrl, engine.iconURI ? engine.iconURI.spec : null);
do_check_eq(match.reason, "search");
});
add_task(function* no_match() {
do_check_eq(null, yield PriorityUrlProvider.getMatch("test"));
do_check_eq(null, yield PlacesSearchAutocompleteProvider.findMatchByToken("test"));
});
add_task(function* hide_search_engine_nomatch() {
@ -29,20 +28,19 @@ add_task(function* hide_search_engine_nomatch() {
Services.search.removeEngine(engine);
yield promiseTopic;
do_check_true(engine.hidden);
do_check_eq(null, yield PriorityUrlProvider.getMatch(token.substr(0, 1)));
do_check_eq(null, yield PlacesSearchAutocompleteProvider.findMatchByToken(token.substr(0, 1)));
});
add_task(function* add_search_engine_match() {
let promiseTopic = promiseSearchTopic("engine-added");
do_check_eq(null, yield PriorityUrlProvider.getMatch("bacon"));
do_check_eq(null, yield PlacesSearchAutocompleteProvider.findMatchByToken("bacon"));
Services.search.addEngineWithDetails("bacon", "", "bacon", "Search Bacon",
"GET", "http://www.bacon.moz/?search={searchTerms}");
yield promiseSearchTopic;
let match = yield PriorityUrlProvider.getMatch("bacon");
let match = yield PlacesSearchAutocompleteProvider.findMatchByToken("bacon");
do_check_eq(match.url, "http://www.bacon.moz");
do_check_eq(match.title, "bacon");
do_check_eq(match.engineName, "bacon");
do_check_eq(match.iconUrl, null);
do_check_eq(match.reason, "search");
});
add_task(function* remove_search_engine_nomatch() {
@ -50,7 +48,21 @@ add_task(function* remove_search_engine_nomatch() {
let promiseTopic = promiseSearchTopic("engine-removed");
Services.search.removeEngine(engine);
yield promiseTopic;
do_check_eq(null, yield PriorityUrlProvider.getMatch("bacon"));
do_check_eq(null, yield PlacesSearchAutocompleteProvider.findMatchByToken("bacon"));
});
add_task(function* test_parseSubmissionURL_basic() {
// Most of the logic of parseSubmissionURL is tested in the search service
// itself, thus we only do a sanity check of the wrapper here.
let engine = yield promiseDefaultSearchEngine();
let submissionURL = engine.getSubmission("terms").uri.spec;
let result = PlacesSearchAutocompleteProvider.parseSubmissionURL(submissionURL);
do_check_eq(result.engineName, engine.name);
do_check_eq(result.terms, "terms");
let result = PlacesSearchAutocompleteProvider.parseSubmissionURL("http://example.org/");
do_check_eq(result, null);
});
function promiseDefaultSearchEngine() {

View File

@ -115,6 +115,7 @@ skip-if = true
[test_pageGuid_bookmarkGuid.js]
[test_frecency_observers.js]
[test_placeURIs.js]
[test_PlacesSearchAutocompleteProvider.js]
[test_PlacesUtils_asyncGetBookmarkIds.js]
[test_PlacesUtils_lazyobservers.js]
[test_placesTxn.js]
@ -125,7 +126,6 @@ skip-if = os == "android"
# Bug 676989: test hangs consistently on Android
skip-if = os == "android"
[test_preventive_maintenance_runTasks.js]
[test_priorityUrlProvider.js]
[test_promiseBookmarksTree.js]
[test_removeVisitsByTimeframe.js]
# Bug 676989: test hangs consistently on Android

View File

@ -1436,6 +1436,20 @@ extends="chrome://global/content/bindings/popup.xml#popup">
type = types.join(" ");
}
// Check if we have a search engine name
let searchEngine = "";
let searchIndex = types.indexOf("search");
if (searchIndex >= 0) {
const TITLE_SEARCH_ENGINE_SEPARATOR = " \u00B7\u2013\u00B7 ";
[title, searchEngine] = title.split(TITLE_SEARCH_ENGINE_SEPARATOR);
// Remove the "search" substring so that the correct style, if any,
// is applied below.
types.splice(searchIndex, 1);
type = types.join(" ");
}
// If we have a tag match, show the tags and icon
if (type == "tag") {
// Configure the extra box for tags display
@ -1496,7 +1510,12 @@ extends="chrome://global/content/bindings/popup.xml#popup">
// Emphasize the matching search terms for the description
this._setUpDescription(this._title, title);
this._setUpDescription(this._url, url);
if (!searchEngine) {
this._setUpDescription(this._url, url);
} else {
// The search engine name, when present, is not emphasized.
this._setUpDescription(this._url, searchEngine, true);
}
// Set up overflow on a timeout because the contents of the box
// might not have a width yet even though we just changed them

View File

@ -363,7 +363,7 @@ var NodeActor = exports.NodeActor = protocol.ActorClass({
}
let global = Cu.getGlobalForObject(listener);
let globalDO = dbg.makeGlobalObjectReference(global);
let globalDO = dbg.addDebuggee(global);
let listenerDO = globalDO.makeDebuggeeValue(listener);
// If the listener is an object with a 'handleEvent' method, use that.
@ -445,6 +445,7 @@ var NodeActor = exports.NodeActor = protocol.ActorClass({
searchString: searchString
});
}
dbg.removeAllDebuggees();
return events;
},

View File

@ -32,7 +32,7 @@ const REGEX_MATCH_FUNCTION_NAME = /^\(?function\s+([^(\s]+)\s*\(/;
const REGEX_MATCH_FUNCTION_ARGS = /^\(?function\s*[^\s(]*\s*\((.+?)\)/;
// Number of terminal entries for the self-xss prevention to go away
const CONSOLE_ENTRY_THRESHOLD = 10
const CONSOLE_ENTRY_THRESHOLD = 5
let WebConsoleUtils = {
/**
* Convenience function to unwrap a wrapped object.