mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge fx-team to m-c. a=merge
This commit is contained in:
commit
c300f93ef4
@ -152,6 +152,7 @@ pref("dom.disable_open_during_load", true);
|
||||
pref("privacy.popups.showBrowserMessage", true);
|
||||
|
||||
pref("keyword.enabled", true);
|
||||
pref("browser.fixup.domainwhitelist.localhost", true);
|
||||
|
||||
pref("accessibility.typeaheadfind", false);
|
||||
pref("accessibility.typeaheadfind.timeout", 5000);
|
||||
|
File diff suppressed because one or more lines are too long
@ -276,6 +276,14 @@ var gPluginHandler = {
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventType == "PluginCrashed" &&
|
||||
!(event.target instanceof Ci.nsIObjectLoadingContent)) {
|
||||
// If the event target is not a plugin object (i.e., an <object> or
|
||||
// <embed> element), this call is for a window-global plugin.
|
||||
this.pluginInstanceCrashed(event.target, event);
|
||||
return;
|
||||
}
|
||||
|
||||
let plugin = event.target;
|
||||
let doc = plugin.ownerDocument;
|
||||
|
||||
@ -1143,7 +1151,7 @@ var gPluginHandler = {
|
||||
|
||||
// Crashed-plugin event listener. Called for every instance of a
|
||||
// plugin in content.
|
||||
pluginInstanceCrashed: function (plugin, aEvent) {
|
||||
pluginInstanceCrashed: function (target, aEvent) {
|
||||
// Ensure the plugin and event are of the right type.
|
||||
if (!(aEvent instanceof Ci.nsIDOMCustomEvent))
|
||||
return;
|
||||
@ -1161,18 +1169,22 @@ var gPluginHandler = {
|
||||
|
||||
let messageString = gNavigatorBundle.getFormattedString("crashedpluginsMessage.title", [pluginName]);
|
||||
|
||||
//
|
||||
// Configure the crashed-plugin placeholder.
|
||||
//
|
||||
let plugin = null, doc;
|
||||
if (target instanceof Ci.nsIObjectLoadingContent) {
|
||||
plugin = target;
|
||||
doc = plugin.ownerDocument;
|
||||
} else {
|
||||
doc = target.document;
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
// doPrompt is specific to the crashed plugin overlay, and
|
||||
// therefore is not applicable for window-global plugins.
|
||||
doPrompt = false;
|
||||
}
|
||||
|
||||
// Force a layout flush so the binding is attached.
|
||||
plugin.clientTop;
|
||||
let overlay = this.getPluginUI(plugin, "main");
|
||||
let statusDiv = this.getPluginUI(plugin, "submitStatus");
|
||||
let doc = plugin.ownerDocument;
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
let status;
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
// Determine which message to show regarding crash reports.
|
||||
if (submittedReport) { // submitReports && !doPrompt, handled in observer
|
||||
status = "submitted";
|
||||
@ -1180,31 +1192,15 @@ var gPluginHandler = {
|
||||
else if (!submitReports && !doPrompt) {
|
||||
status = "noSubmit";
|
||||
}
|
||||
else { // doPrompt
|
||||
else if (!pluginDumpID) {
|
||||
// If we don't have a minidumpID, we can't (or didn't) submit anything.
|
||||
// This can happen if the plugin is killed from the task manager.
|
||||
status = "noReport";
|
||||
}
|
||||
else {
|
||||
status = "please";
|
||||
this.getPluginUI(plugin, "submitButton").addEventListener("click",
|
||||
function (event) {
|
||||
if (event.button != 0 || !event.isTrusted)
|
||||
return;
|
||||
this.submitReport(pluginDumpID, browserDumpID, plugin);
|
||||
pref.setBoolPref("", optInCB.checked);
|
||||
}.bind(this));
|
||||
let optInCB = this.getPluginUI(plugin, "submitURLOptIn");
|
||||
let pref = Services.prefs.getBranch("dom.ipc.plugins.reportCrashURL");
|
||||
optInCB.checked = pref.getBoolPref("");
|
||||
}
|
||||
|
||||
// If we don't have a minidumpID, we can't (or didn't) submit anything.
|
||||
// This can happen if the plugin is killed from the task manager.
|
||||
if (!pluginDumpID) {
|
||||
status = "noReport";
|
||||
}
|
||||
|
||||
statusDiv.setAttribute("status", status);
|
||||
|
||||
let helpIcon = this.getPluginUI(plugin, "helpIcon");
|
||||
this.addLinkClickCallback(helpIcon, "openHelpPage");
|
||||
|
||||
// If we're showing the link to manually trigger report submission, we'll
|
||||
// want to be able to update all the instances of the UI for this crash to
|
||||
// show an updated message when a report is submitted.
|
||||
@ -1238,26 +1234,15 @@ var gPluginHandler = {
|
||||
}
|
||||
#endif
|
||||
|
||||
let crashText = this.getPluginUI(plugin, "crashedText");
|
||||
crashText.textContent = messageString;
|
||||
|
||||
let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
|
||||
|
||||
let link = this.getPluginUI(plugin, "reloadLink");
|
||||
this.addLinkClickCallback(link, "reloadPage", browser);
|
||||
|
||||
let notificationBox = gBrowser.getNotificationBox(browser);
|
||||
let isShowing = false;
|
||||
|
||||
let isShowing = this.shouldShowOverlay(plugin, overlay);
|
||||
|
||||
// Is the <object>'s size too small to hold what we want to show?
|
||||
if (!isShowing) {
|
||||
// First try hiding the crash report submission UI.
|
||||
statusDiv.removeAttribute("status");
|
||||
|
||||
isShowing = this.shouldShowOverlay(plugin, overlay);
|
||||
if (plugin) {
|
||||
// If there's no plugin (an <object> or <embed> element), this call is
|
||||
// for a window-global plugin. In this case, there's no overlay to show.
|
||||
isShowing = _setUpPluginOverlay.call(this, plugin, doPrompt, browser);
|
||||
}
|
||||
this.setVisibility(plugin, overlay, isShowing);
|
||||
|
||||
if (isShowing) {
|
||||
// If a previous plugin on the page was too small and resulted in adding a
|
||||
@ -1330,5 +1315,54 @@ var gPluginHandler = {
|
||||
}, false);
|
||||
}
|
||||
|
||||
// Configure the crashed-plugin placeholder.
|
||||
// Returns true if the plugin overlay is visible.
|
||||
function _setUpPluginOverlay(plugin, doPromptSubmit, browser) {
|
||||
if (!plugin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Force a layout flush so the binding is attached.
|
||||
plugin.clientTop;
|
||||
let overlay = this.getPluginUI(plugin, "main");
|
||||
let statusDiv = this.getPluginUI(plugin, "submitStatus");
|
||||
|
||||
if (doPromptSubmit) {
|
||||
this.getPluginUI(plugin, "submitButton").addEventListener("click",
|
||||
function (event) {
|
||||
if (event.button != 0 || !event.isTrusted)
|
||||
return;
|
||||
this.submitReport(pluginDumpID, browserDumpID, plugin);
|
||||
pref.setBoolPref("", optInCB.checked);
|
||||
}.bind(this));
|
||||
let optInCB = this.getPluginUI(plugin, "submitURLOptIn");
|
||||
let pref = Services.prefs.getBranch("dom.ipc.plugins.reportCrashURL");
|
||||
optInCB.checked = pref.getBoolPref("");
|
||||
}
|
||||
|
||||
statusDiv.setAttribute("status", status);
|
||||
|
||||
let helpIcon = this.getPluginUI(plugin, "helpIcon");
|
||||
this.addLinkClickCallback(helpIcon, "openHelpPage");
|
||||
|
||||
let crashText = this.getPluginUI(plugin, "crashedText");
|
||||
crashText.textContent = messageString;
|
||||
|
||||
let link = this.getPluginUI(plugin, "reloadLink");
|
||||
this.addLinkClickCallback(link, "reloadPage", browser);
|
||||
|
||||
let isShowing = this.shouldShowOverlay(plugin, overlay);
|
||||
|
||||
// Is the <object>'s size too small to hold what we want to show?
|
||||
if (!isShowing) {
|
||||
// First try hiding the crash report submission UI.
|
||||
statusDiv.removeAttribute("status");
|
||||
|
||||
isShowing = this.shouldShowOverlay(plugin, overlay);
|
||||
}
|
||||
this.setVisibility(plugin, overlay, isShowing);
|
||||
|
||||
return isShowing;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -22,6 +22,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
|
||||
"resource://gre/modules/ShortcutUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
|
||||
"@mozilla.org/network/dns-service;1",
|
||||
"nsIDNSService");
|
||||
|
||||
const nsIWebNavigation = Ci.nsIWebNavigation;
|
||||
|
||||
var gLastBrowserCharset = null;
|
||||
@ -745,6 +749,101 @@ const gFormSubmitObserver = {
|
||||
}
|
||||
};
|
||||
|
||||
function gKeywordURIFixup(fixupInfo, topic, data) {
|
||||
fixupInfo.QueryInterface(Ci.nsIURIFixupInfo);
|
||||
|
||||
// We get called irrespective of whether we did a keyword search, or
|
||||
// whether the original input would be vaguely interpretable as a URL,
|
||||
// so figure that out first.
|
||||
let alternativeURI = fixupInfo.fixedURI;
|
||||
if (!fixupInfo.fixupUsedKeyword || !alternativeURI) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We should have a document loader...
|
||||
let docshellRef = fixupInfo.consumer;
|
||||
try {
|
||||
docshellRef.QueryInterface(Ci.nsIDocumentLoader);
|
||||
} catch (ex) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ... from which we can deduce the browser
|
||||
let browser = gBrowser.getBrowserForDocument(docshellRef.document);
|
||||
if (!browser)
|
||||
return;
|
||||
|
||||
// At this point we're still only just about to load this URI.
|
||||
// When the async DNS lookup comes back, we may be in any of these states:
|
||||
// 1) still on the previous URI, waiting for the preferredURI (keyword
|
||||
// search) to respond;
|
||||
// 2) at the keyword search URI (preferredURI)
|
||||
// 3) at some other page because the user stopped navigation.
|
||||
// We keep track of the currentURI to detect case (1) in the DNS lookup
|
||||
// callback.
|
||||
let previousURI = browser.currentURI;
|
||||
|
||||
// now swap for a weak ref so we don't hang on to browser needlessly
|
||||
// even if the DNS query takes forever
|
||||
let weakBrowser = Cu.getWeakReference(browser);
|
||||
browser = null;
|
||||
|
||||
// Additionally, we need the host of the parsed url
|
||||
let hostName = alternativeURI.host;
|
||||
// and the ascii-only host for the pref:
|
||||
let asciiHost = alternativeURI.asciiHost;
|
||||
|
||||
let onLookupComplete = (request, record, status) => {
|
||||
let browser = weakBrowser.get();
|
||||
if (!Components.isSuccessCode(status) || !browser)
|
||||
return;
|
||||
|
||||
let currentURI = browser.currentURI;
|
||||
// If we're in case (3) (see above), don't show an info bar.
|
||||
if (!currentURI.equals(previousURI) &&
|
||||
!currentURI.equals(fixupInfo.preferredURI)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// show infobar offering to visit the host
|
||||
let notificationBox = gBrowser.getNotificationBox(browser);
|
||||
if (notificationBox.getNotificationWithValue("keyword-uri-fixup"))
|
||||
return;
|
||||
|
||||
let message = gNavigatorBundle.getFormattedString(
|
||||
"keywordURIFixup.message", [hostName]);
|
||||
let yesMessage = gNavigatorBundle.getFormattedString(
|
||||
"keywordURIFixup.goTo", [hostName])
|
||||
|
||||
let buttons = [
|
||||
{
|
||||
label: yesMessage,
|
||||
accessKey: gNavigatorBundle.getString("keywordURIFixup.goTo.accesskey"),
|
||||
callback: function() {
|
||||
let pref = "browser.fixup.domainwhitelist." + asciiHost;
|
||||
Services.prefs.setBoolPref(pref, true);
|
||||
openUILinkIn(alternativeURI.spec, "current");
|
||||
}
|
||||
},
|
||||
{
|
||||
label: gNavigatorBundle.getString("keywordURIFixup.dismiss"),
|
||||
accessKey: gNavigatorBundle.getString("keywordURIFixup.dismiss.accesskey"),
|
||||
callback: function() {
|
||||
let notification = notificationBox.getNotificationWithValue("keyword-uri-fixup");
|
||||
notificationBox.removeNotification(notification, true);
|
||||
}
|
||||
}
|
||||
];
|
||||
let notification =
|
||||
notificationBox.appendNotification(message,"keyword-uri-fixup", null,
|
||||
notificationBox.PRIORITY_INFO_HIGH,
|
||||
buttons);
|
||||
notification.persistence = 1;
|
||||
};
|
||||
|
||||
gDNSService.asyncResolve(hostName, 0, onLookupComplete, Services.tm.mainThread);
|
||||
}
|
||||
|
||||
var gBrowserInit = {
|
||||
delayedStartupFinished: false,
|
||||
|
||||
@ -1051,6 +1150,7 @@ var gBrowserInit = {
|
||||
Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
|
||||
Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
|
||||
Services.obs.addObserver(gFormSubmitObserver, "invalidformsubmit", false);
|
||||
Services.obs.addObserver(gKeywordURIFixup, "keyword-uri-fixup", false);
|
||||
|
||||
BrowserOffline.init();
|
||||
OfflineApps.init();
|
||||
@ -1354,6 +1454,7 @@ var gBrowserInit = {
|
||||
Services.obs.removeObserver(gXPInstallObserver, "addon-install-failed");
|
||||
Services.obs.removeObserver(gXPInstallObserver, "addon-install-complete");
|
||||
Services.obs.removeObserver(gFormSubmitObserver, "invalidformsubmit");
|
||||
Services.obs.removeObserver(gKeywordURIFixup, "keyword-uri-fixup");
|
||||
|
||||
try {
|
||||
gPrefService.removeObserver(gHomeButton.prefDomain, gHomeButton);
|
||||
|
@ -401,6 +401,7 @@ skip-if = e10s # Bug 932651 - getClipboardData in specialpowersAPI.js not e10s f
|
||||
skip-if = e10s # Bug ?????? - obscure non-windows child process crashes on try
|
||||
[browser_urlbarRevert.js]
|
||||
skip-if = e10s # Bug ?????? - ESC reverted the location bar value - Got foobar, expected example.com
|
||||
[browser_urlbarSearchSingleWordNotification.js]
|
||||
[browser_urlbarStop.js]
|
||||
skip-if = e10s # Bug ????? - test calls gBrowser.contentWindow.stop
|
||||
[browser_urlbarTrimURLs.js]
|
||||
|
@ -107,8 +107,8 @@ function test() {
|
||||
});
|
||||
|
||||
Services.prefs.setBoolPref(PREF_PRELOAD, false);
|
||||
// set directory source to empty links
|
||||
Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, "data:application/json,{}");
|
||||
// set directory source to dummy/empty links
|
||||
Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, 'data:application/json,{"test":1}');
|
||||
}
|
||||
|
||||
let observer = {
|
||||
|
@ -0,0 +1,80 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref("browser.fixup.domainwhitelist.localhost");
|
||||
});
|
||||
|
||||
function promiseNotificationForTab(value, expected, tab=gBrowser.selectedTab) {
|
||||
let deferred = Promise.defer();
|
||||
let notificationBox = gBrowser.getNotificationBox(tab.linkedBrowser);
|
||||
if (expected) {
|
||||
waitForCondition(() => notificationBox.getNotificationWithValue(value) !== null,
|
||||
deferred.resolve, "Were expecting to get a notification");
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
is(notificationBox.getNotificationWithValue(value), null, "We are expecting to not get a notification");
|
||||
deferred.resolve();
|
||||
}, 1000);
|
||||
}
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function* runURLBarSearchTest(valueToOpen, expectSearch, expectNotification) {
|
||||
gURLBar.value = valueToOpen;
|
||||
let expectedURI;
|
||||
if (!expectSearch) {
|
||||
expectedURI = "http://" + valueToOpen + "/";
|
||||
} else {
|
||||
yield new Promise(resolve => {
|
||||
Services.search.init(resolve)
|
||||
});
|
||||
expectedURI = Services.search.defaultEngine.getSubmission(valueToOpen, null, "keyword").uri.spec;
|
||||
}
|
||||
gURLBar.focus();
|
||||
let docLoadPromise = waitForDocLoadAndStopIt(expectedURI);
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
|
||||
yield docLoadPromise;
|
||||
|
||||
yield promiseNotificationForTab("keyword-uri-fixup", expectNotification);
|
||||
}
|
||||
|
||||
add_task(function* test_navigate_full_domain() {
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
yield* runURLBarSearchTest("www.mozilla.org", false, false);
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(function* test_navigate_single_host() {
|
||||
Services.prefs.setBoolPref("browser.fixup.domainwhitelist.localhost", false);
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
yield* runURLBarSearchTest("localhost", true, true);
|
||||
|
||||
let notificationBox = gBrowser.getNotificationBox(tab.linkedBrowser);
|
||||
let notification = notificationBox.getNotificationWithValue("keyword-uri-fixup");
|
||||
let docLoadPromise = waitForDocLoadAndStopIt("http://localhost/");
|
||||
notification.querySelector(".notification-button-default").click();
|
||||
|
||||
// check pref value
|
||||
let pref = "browser.fixup.domainwhitelist.localhost";
|
||||
let prefValue = Services.prefs.getBoolPref(pref);
|
||||
ok(prefValue, "Pref should have been toggled");
|
||||
|
||||
yield docLoadPromise;
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
// Now try again with the pref set.
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
yield* runURLBarSearchTest("localhost", false, false);
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(function* test_navigate_invalid_url() {
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
yield* runURLBarSearchTest("mozilla is awesome", true, false);
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
@ -24,8 +24,8 @@ let isLinux = ("@mozilla.org/gnome-gconf-service;1" in Cc);
|
||||
let isWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
|
||||
let gWindow = window;
|
||||
|
||||
// Default to empty directory links
|
||||
let gDirectorySource = "data:application/json,{}";
|
||||
// Default to dummy/empty directory links
|
||||
let gDirectorySource = 'data:application/json,{"test":1}';
|
||||
|
||||
// The tests assume all three rows of sites are shown, but the window may be too
|
||||
// short to actually show three rows. Resize it if necessary.
|
||||
|
@ -62,6 +62,7 @@ run-if = crashreporter
|
||||
[browser_CTP_notificationBar.js]
|
||||
[browser_CTP_outsideScrollArea.js]
|
||||
[browser_CTP_resize.js]
|
||||
[browser_globalplugin_crashinfobar.js]
|
||||
[browser_pageInfo_plugins.js]
|
||||
[browser_pluginnotification.js]
|
||||
[browser_pluginplaypreview.js]
|
||||
|
@ -0,0 +1,69 @@
|
||||
/* 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/. */
|
||||
|
||||
let gTestBrowser = null;
|
||||
|
||||
let propBagProperties = {
|
||||
pluginName: "GlobalTestPlugin",
|
||||
pluginDumpID: "1234",
|
||||
browserDumpID: "5678",
|
||||
submittedCrashReport: false
|
||||
}
|
||||
|
||||
// Test that plugin crash submissions still work properly after
|
||||
// click-to-play activation.
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
let tab = gBrowser.loadOneTab("about:blank", { inBackground: false });
|
||||
gTestBrowser = gBrowser.getBrowserForTab(tab);
|
||||
gTestBrowser.addEventListener("PluginCrashed", onCrash, false);
|
||||
gTestBrowser.addEventListener("load", onPageLoad, true);
|
||||
|
||||
registerCleanupFunction(function cleanUp() {
|
||||
gTestBrowser.removeEventListener("PluginCrashed", onCrash, false);
|
||||
gTestBrowser.removeEventListener("load", onPageLoad, true);
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
}
|
||||
|
||||
function onPageLoad() {
|
||||
executeSoon(generateCrashEvent);
|
||||
}
|
||||
|
||||
function generateCrashEvent() {
|
||||
let window = gTestBrowser.contentWindow;
|
||||
let propBag = Cc["@mozilla.org/hash-property-bag;1"]
|
||||
.createInstance(Ci.nsIWritablePropertyBag);
|
||||
for (let [name, val] of Iterator(propBagProperties)) {
|
||||
propBag.setProperty(name, val);
|
||||
}
|
||||
|
||||
let event = window.document.createEvent("CustomEvent");
|
||||
event.initCustomEvent("PluginCrashed", true, true, propBag);
|
||||
window.dispatchEvent(event);
|
||||
}
|
||||
|
||||
|
||||
function onCrash(event) {
|
||||
let target = event.target;
|
||||
is (target, gTestBrowser.contentWindow, "Event target is the window.");
|
||||
|
||||
let propBag = event.detail.QueryInterface(Ci.nsIPropertyBag2);
|
||||
for (let [name, val] of Iterator(propBagProperties)) {
|
||||
let type = typeof val;
|
||||
let propVal = type == "string"
|
||||
? propBag.getPropertyAsAString(name)
|
||||
: propBag.getPropertyAsBool(name);
|
||||
is (propVal, val, "Correct property in detail propBag: " + name + ".");
|
||||
}
|
||||
|
||||
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
|
||||
let notification = notificationBox.getNotificationWithValue("plugin-crashed");
|
||||
|
||||
ok(notification, "Infobar was shown.");
|
||||
is(notification.priority, notificationBox.PRIORITY_WARNING_MEDIUM, "Correct priority.");
|
||||
is(notification.getAttribute("label"), "The GlobalTestPlugin plugin has crashed.", "Correct message.");
|
||||
finish();
|
||||
}
|
@ -28,7 +28,6 @@ support-files =
|
||||
[browser_aboutHome_activation.js]
|
||||
[browser_addons.js]
|
||||
[browser_blocklist.js]
|
||||
[browser_defaults.js]
|
||||
[browser_share.js]
|
||||
[browser_social_activation.js]
|
||||
[browser_social_chatwindow.js]
|
||||
|
@ -8,7 +8,7 @@ const ID_SUFFIX = "@services.mozilla.org";
|
||||
const STRING_TYPE_NAME = "type.%ID%.name";
|
||||
const XPINSTALL_URL = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
|
||||
|
||||
let manifest = { // builtin provider
|
||||
let manifest = {
|
||||
name: "provider 1",
|
||||
origin: "https://example.com",
|
||||
sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html",
|
||||
@ -28,19 +28,15 @@ function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let prefname = getManifestPrefname(manifest);
|
||||
setBuiltinManifestPref(prefname, manifest);
|
||||
// ensure that manifest2 is NOT showing as builtin
|
||||
is(SocialService.getOriginActivationType(manifest.origin), "builtin", "manifest is builtin");
|
||||
is(SocialService.getOriginActivationType(manifest2.origin), "foreign", "manifest2 is not builtin");
|
||||
is(SocialService.getOriginActivationType(manifest.origin), "foreign", "manifest is foreign");
|
||||
is(SocialService.getOriginActivationType(manifest2.origin), "foreign", "manifest2 is foreign");
|
||||
|
||||
Services.prefs.setBoolPref("social.remote-install.enabled", true);
|
||||
runSocialTests(tests, undefined, undefined, function () {
|
||||
Services.prefs.clearUserPref("social.remote-install.enabled");
|
||||
// clear our builtin pref
|
||||
ok(!Services.prefs.prefHasUserValue(prefname), "manifest is not in user-prefs");
|
||||
resetBuiltinManifestPref(prefname);
|
||||
// just in case the tests failed, clear these here as well
|
||||
Services.prefs.clearUserPref("social.whitelist");
|
||||
Services.prefs.clearUserPref("social.directories");
|
||||
finish();
|
||||
});
|
||||
@ -169,9 +165,9 @@ var tests = {
|
||||
|
||||
expectEvent = "onEnabling";
|
||||
setManifestPref(prefname, manifest);
|
||||
SocialService.addBuiltinProvider(manifest.origin, function(provider) {
|
||||
SocialService.enableProvider(manifest.origin, function(provider) {
|
||||
expectEvent = "onDisabling";
|
||||
SocialService.removeProvider(provider.origin, function() {
|
||||
SocialService.disableProvider(provider.origin, function() {
|
||||
AddonManager.removeAddonListener(listener);
|
||||
Services.prefs.clearUserPref(prefname);
|
||||
next();
|
||||
@ -199,83 +195,7 @@ var tests = {
|
||||
is(SocialService.getOriginActivationType(installFrom), "foreign", "testing foriegn install");
|
||||
Social.installProvider(doc, manifest2, function(addonManifest) {
|
||||
Services.prefs.clearUserPref("social.whitelist");
|
||||
SocialService.addBuiltinProvider(addonManifest.origin, function(provider) {
|
||||
Social.uninstallProvider(addonManifest.origin);
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
testBuiltinInstallWithoutManifest: function(next) {
|
||||
// send installProvider null for the manifest
|
||||
AddonManager.addAddonListener(installListener(next, manifest));
|
||||
let panel = document.getElementById("servicesInstall-notification");
|
||||
PopupNotifications.panel.addEventListener("popupshown", function onpopupshown() {
|
||||
PopupNotifications.panel.removeEventListener("popupshown", onpopupshown);
|
||||
info("servicesInstall-notification panel opened");
|
||||
panel.button.click();
|
||||
});
|
||||
|
||||
let prefname = getManifestPrefname(manifest);
|
||||
let activationURL = manifest.origin + "/browser/browser/base/content/test/social/social_activate.html"
|
||||
addTab(activationURL, function(tab) {
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
let installFrom = doc.nodePrincipal.origin;
|
||||
is(SocialService.getOriginActivationType(installFrom), "builtin", "testing builtin install");
|
||||
ok(!Services.prefs.prefHasUserValue(prefname), "manifest is not in user-prefs");
|
||||
Social.installProvider(doc, null, function(addonManifest) {
|
||||
ok(Services.prefs.prefHasUserValue(prefname), "manifest is in user-prefs");
|
||||
SocialService.addBuiltinProvider(addonManifest.origin, function(provider) {
|
||||
Social.uninstallProvider(addonManifest.origin);
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
testBuiltinInstall: function(next) {
|
||||
// send installProvider a json object for the manifest
|
||||
AddonManager.addAddonListener(installListener(next, manifest));
|
||||
let panel = document.getElementById("servicesInstall-notification");
|
||||
PopupNotifications.panel.addEventListener("popupshown", function onpopupshown() {
|
||||
PopupNotifications.panel.removeEventListener("popupshown", onpopupshown);
|
||||
info("servicesInstall-notification panel opened");
|
||||
panel.button.click();
|
||||
});
|
||||
|
||||
let prefname = getManifestPrefname(manifest);
|
||||
let activationURL = manifest.origin + "/browser/browser/base/content/test/social/social_activate.html"
|
||||
addTab(activationURL, function(tab) {
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
let installFrom = doc.nodePrincipal.origin;
|
||||
is(SocialService.getOriginActivationType(installFrom), "builtin", "testing builtin install");
|
||||
ok(!Services.prefs.prefHasUserValue(prefname), "manifest is not in user-prefs");
|
||||
Social.installProvider(doc, manifest, function(addonManifest) {
|
||||
ok(Services.prefs.prefHasUserValue(prefname), "manifest is in user-prefs");
|
||||
SocialService.addBuiltinProvider(addonManifest.origin, function(provider) {
|
||||
Social.uninstallProvider(addonManifest.origin);
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
testWhitelistInstall: function(next) {
|
||||
AddonManager.addAddonListener(installListener(next, manifest2));
|
||||
let panel = document.getElementById("servicesInstall-notification");
|
||||
PopupNotifications.panel.addEventListener("popupshown", function onpopupshown() {
|
||||
PopupNotifications.panel.removeEventListener("popupshown", onpopupshown);
|
||||
info("servicesInstall-notification panel opened");
|
||||
panel.button.click();
|
||||
});
|
||||
|
||||
let activationURL = manifest2.origin + "/browser/browser/base/content/test/social/social_activate.html"
|
||||
addTab(activationURL, function(tab) {
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
let installFrom = doc.nodePrincipal.origin;
|
||||
Services.prefs.setCharPref("social.whitelist", installFrom);
|
||||
is(SocialService.getOriginActivationType(installFrom), "whitelist", "testing whitelist install");
|
||||
Social.installProvider(doc, manifest2, function(addonManifest) {
|
||||
Services.prefs.clearUserPref("social.whitelist");
|
||||
SocialService.addBuiltinProvider(addonManifest.origin, function(provider) {
|
||||
SocialService.enableProvider(addonManifest.origin, function(provider) {
|
||||
Social.uninstallProvider(addonManifest.origin);
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
@ -299,7 +219,7 @@ var tests = {
|
||||
is(SocialService.getOriginActivationType(installFrom), "directory", "testing directory install");
|
||||
Social.installProvider(doc, manifest2, function(addonManifest) {
|
||||
Services.prefs.clearUserPref("social.directories");
|
||||
SocialService.addBuiltinProvider(addonManifest.origin, function(provider) {
|
||||
SocialService.enableProvider(addonManifest.origin, function(provider) {
|
||||
Social.uninstallProvider(addonManifest.origin);
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
@ -322,7 +242,7 @@ var tests = {
|
||||
let installFrom = doc.nodePrincipal.origin;
|
||||
Services.prefs.setCharPref("social.whitelist", installFrom);
|
||||
Social.installProvider(doc, manifest2, function(addonManifest) {
|
||||
SocialService.addBuiltinProvider(addonManifest.origin, function(provider) {
|
||||
SocialService.enableProvider(addonManifest.origin, function(provider) {
|
||||
is(provider.manifest.version, 1, "manifest version is 1");
|
||||
|
||||
// watch for the provider-update and test the new version
|
||||
|
@ -60,12 +60,12 @@ var tests = {
|
||||
try {
|
||||
SocialService.addProvider(manifest, function(provider) {
|
||||
try {
|
||||
SocialService.removeProvider(provider.origin, function() {
|
||||
SocialService.disableProvider(provider.origin, function() {
|
||||
ok(true, "added and removed provider");
|
||||
finishTest(true);
|
||||
});
|
||||
} catch(e) {
|
||||
ok(false, "SocialService.removeProvider threw exception: " + e);
|
||||
ok(false, "SocialService.disableProvider threw exception: " + e);
|
||||
finishTest(false);
|
||||
}
|
||||
});
|
||||
@ -85,7 +85,7 @@ var tests = {
|
||||
setAndUpdateBlocklist(blocklistURL, function() {
|
||||
try {
|
||||
SocialService.addProvider(manifest_bad, function(provider) {
|
||||
SocialService.removeProvider(provider.origin, function() {
|
||||
SocialService.disableProvider(provider.origin, function() {
|
||||
ok(false, "SocialService.addProvider should throw blocklist exception");
|
||||
finishTest(false);
|
||||
});
|
||||
|
@ -1,14 +0,0 @@
|
||||
|
||||
let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
|
||||
|
||||
// this test ensures that any builtin providers have the builtin flag that we
|
||||
// need to help with "install" of a builtin.
|
||||
function test() {
|
||||
let manifestPrefs = Services.prefs.getDefaultBranch("social.manifest.");
|
||||
let prefs = manifestPrefs.getChildList("", []);
|
||||
ok(prefs.length > 0, "we have builtin providers");
|
||||
for (let pref of prefs) {
|
||||
let manifest = JSON.parse(manifestPrefs.getComplexValue(pref, Ci.nsISupportsString).data);
|
||||
ok(manifest.builtin, "manifest is builtin " + manifest.origin);
|
||||
}
|
||||
}
|
@ -115,7 +115,7 @@ var tests = {
|
||||
is(shareButton.getAttribute("disabled"), "true", "share button attribute is disabled");
|
||||
// button should be visible
|
||||
is(shareButton.hidden, false, "share button is visible");
|
||||
SocialService.removeProvider(manifest.origin, next);
|
||||
SocialService.disableProvider(manifest.origin, next);
|
||||
});
|
||||
},
|
||||
testShareEnabledOnActivation: function(next) {
|
||||
@ -163,7 +163,7 @@ var tests = {
|
||||
if (testData) {
|
||||
executeSoon(runOneTest);
|
||||
} else {
|
||||
SocialService.removeProvider(manifest.origin, next);
|
||||
SocialService.disableProvider(manifest.origin, next);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -227,7 +227,7 @@ var tests = {
|
||||
case "got-share-data-message":
|
||||
is(JSON.stringify(e.data.result), expecting, "microdata data ok");
|
||||
gBrowser.removeTab(testTab);
|
||||
SocialService.removeProvider(manifest.origin, next);
|
||||
SocialService.disableProvider(manifest.origin, next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,29 @@ let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).So
|
||||
|
||||
let tabsToRemove = [];
|
||||
|
||||
|
||||
function removeAllProviders(callback) {
|
||||
// all the providers may have been added.
|
||||
function removeProviders() {
|
||||
if (Social.providers.length < 1) {
|
||||
executeSoon(function() {
|
||||
is(Social.providers.length, 0, "all providers removed");
|
||||
executeSoon(callback);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// a full install sets the manifest into a pref, addProvider alone doesn't,
|
||||
// make sure we uninstall if the manifest was added.
|
||||
if (Social.providers[0].manifest) {
|
||||
SocialService.uninstallProvider(Social.providers[0].origin, removeProviders);
|
||||
} else {
|
||||
SocialService.disableProvider(Social.providers[0].origin, removeProviders);
|
||||
}
|
||||
}
|
||||
removeProviders();
|
||||
}
|
||||
|
||||
function postTestCleanup(callback) {
|
||||
// any tabs opened by the test.
|
||||
for (let tab of tabsToRemove)
|
||||
@ -15,37 +38,8 @@ function postTestCleanup(callback) {
|
||||
// to fully open - the end result is that the panel might stay open
|
||||
//SocialUI.activationPanel.hidePopup();
|
||||
|
||||
Services.prefs.clearUserPref("social.whitelist");
|
||||
|
||||
// all providers may have had their manifests added.
|
||||
for (let manifest of gProviders)
|
||||
Services.prefs.clearUserPref("social.manifest." + manifest.origin);
|
||||
|
||||
// all the providers may have been added.
|
||||
let providers = gProviders.slice(0)
|
||||
function removeProviders() {
|
||||
if (providers.length < 1) {
|
||||
executeSoon(function() {
|
||||
is(Social.providers.length, 0, "all providers removed");
|
||||
callback();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let provider = providers.pop();
|
||||
try {
|
||||
SocialService.removeProvider(provider.origin, removeProviders);
|
||||
} catch(ex) {
|
||||
removeProviders();
|
||||
}
|
||||
}
|
||||
removeProviders();
|
||||
}
|
||||
|
||||
function addBuiltinManifest(manifest) {
|
||||
let prefname = getManifestPrefname(manifest);
|
||||
setBuiltinManifestPref(prefname, manifest);
|
||||
return prefname;
|
||||
removeAllProviders(callback);
|
||||
}
|
||||
|
||||
function addTab(url, callback) {
|
||||
@ -210,74 +204,52 @@ var tests = {
|
||||
ok(panel.hidden, "activation panel still hidden");
|
||||
checkSocialUI();
|
||||
Services.prefs.clearUserPref("social.remote-install.enabled");
|
||||
next();
|
||||
removeAllProviders(next);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
testIFrameActivation: function(next) {
|
||||
Services.prefs.setCharPref("social.whitelist", gTestDomains.join(","));
|
||||
activateIFrameProvider(gTestDomains[0], function() {
|
||||
is(SocialUI.enabled, false, "SocialUI is not enabled");
|
||||
ok(!SocialSidebar.provider, "provider is not installed");
|
||||
let panel = document.getElementById("servicesInstall-notification");
|
||||
ok(panel.hidden, "activation panel still hidden");
|
||||
checkSocialUI();
|
||||
Services.prefs.clearUserPref("social.whitelist");
|
||||
next();
|
||||
removeAllProviders(next);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
testActivationFirstProvider: function(next) {
|
||||
Services.prefs.setCharPref("social.whitelist", gTestDomains.join(","));
|
||||
// first up we add a manifest entry for a single provider.
|
||||
activateOneProvider(gProviders[0], false, function() {
|
||||
// we deactivated leaving no providers left, so Social is disabled.
|
||||
ok(!SocialSidebar.provider, "should be no provider left after disabling");
|
||||
checkSocialUI();
|
||||
Services.prefs.clearUserPref("social.whitelist");
|
||||
next();
|
||||
removeAllProviders(next);
|
||||
});
|
||||
},
|
||||
|
||||
testActivationBuiltin: function(next) {
|
||||
let prefname = addBuiltinManifest(gProviders[0]);
|
||||
is(SocialService.getOriginActivationType(gTestDomains[0]), "builtin", "manifest is builtin");
|
||||
// first up we add a manifest entry for a single provider.
|
||||
activateOneProvider(gProviders[0], false, function() {
|
||||
// we deactivated leaving no providers left, so Social is disabled.
|
||||
ok(!SocialSidebar.provider, "should be no provider left after disabling");
|
||||
checkSocialUI();
|
||||
resetBuiltinManifestPref(prefname);
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
testActivationMultipleProvider: function(next) {
|
||||
// The trick with this test is to make sure that Social.providers[1] is
|
||||
// the current provider when doing the undo - this makes sure that the
|
||||
// Social code doesn't fallback to Social.providers[0], which it will
|
||||
// do in some cases (but those cases do not include what this test does)
|
||||
// first enable the 2 providers
|
||||
Services.prefs.setCharPref("social.whitelist", gTestDomains.join(","));
|
||||
SocialService.addProvider(gProviders[0], function() {
|
||||
SocialService.addProvider(gProviders[1], function() {
|
||||
checkSocialUI();
|
||||
// activate the last provider.
|
||||
let prefname = addBuiltinManifest(gProviders[2]);
|
||||
activateOneProvider(gProviders[2], false, function() {
|
||||
// we deactivated - the first provider should be enabled.
|
||||
is(SocialSidebar.provider.origin, Social.providers[1].origin, "original provider should have been reactivated");
|
||||
checkSocialUI();
|
||||
Services.prefs.clearUserPref("social.whitelist");
|
||||
resetBuiltinManifestPref(prefname);
|
||||
next();
|
||||
removeAllProviders(next);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
testAddonManagerDoubleInstall: function(next) {
|
||||
Services.prefs.setCharPref("social.whitelist", gTestDomains.join(","));
|
||||
// Create a new tab and load about:addons
|
||||
let blanktab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = blanktab;
|
||||
@ -290,12 +262,11 @@ var tests = {
|
||||
let browser = blanktab.linkedBrowser;
|
||||
is(browser.currentURI.spec, "about:addons", "about:addons should load into blank tab.");
|
||||
|
||||
let prefname = addBuiltinManifest(gProviders[0]);
|
||||
activateOneProvider(gProviders[0], true, function() {
|
||||
info("first activation completed");
|
||||
is(gBrowser.contentDocument.location.href, gProviders[0].origin + "/browser/browser/base/content/test/social/social_postActivation.html");
|
||||
is(gBrowser.contentDocument.location.href, gProviders[0].origin + "/browser/browser/base/content/test/social/social_postActivation.html", "postActivationURL loaded");
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
is(gBrowser.contentDocument.location.href, gProviders[0].origin + "/browser/browser/base/content/test/social/social_activate.html");
|
||||
is(gBrowser.contentDocument.location.href, gProviders[0].origin + "/browser/browser/base/content/test/social/social_activate.html", "activation page selected");
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
tabsToRemove.pop();
|
||||
// uninstall the provider
|
||||
@ -303,7 +274,7 @@ var tests = {
|
||||
checkSocialUI();
|
||||
activateOneProvider(gProviders[0], true, function() {
|
||||
info("second activation completed");
|
||||
is(gBrowser.contentDocument.location.href, gProviders[0].origin + "/browser/browser/base/content/test/social/social_postActivation.html");
|
||||
is(gBrowser.contentDocument.location.href, gProviders[0].origin + "/browser/browser/base/content/test/social/social_postActivation.html", "postActivationURL loaded");
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
|
||||
// after closing the addons tab, verify provider is still installed
|
||||
@ -311,9 +282,7 @@ var tests = {
|
||||
gBrowser.tabContainer.removeEventListener("TabClose", onTabClose);
|
||||
AddonManager.getAddonsByTypes(["service"], function(aAddons) {
|
||||
is(aAddons.length, 1, "there can be only one");
|
||||
Services.prefs.clearUserPref("social.whitelist");
|
||||
resetBuiltinManifestPref(prefname);
|
||||
next();
|
||||
removeAllProviders(next);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -89,7 +89,7 @@ var tests = {
|
||||
is(button.hidden, false, "mark button is visible");
|
||||
|
||||
checkSocialUI(window);
|
||||
SocialService.removeProvider(manifest2.origin, next);
|
||||
SocialService.disableProvider(manifest2.origin, next);
|
||||
});
|
||||
},
|
||||
testNoButtonOnEnable: function(next) {
|
||||
@ -107,7 +107,7 @@ var tests = {
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
Social.installProvider(doc, manifest3, function(addonManifest) {
|
||||
// enable the provider so we know the button would have appeared
|
||||
SocialService.addBuiltinProvider(manifest3.origin, function(provider) {
|
||||
SocialService.enableProvider(manifest3.origin, function(provider) {
|
||||
is(provider.origin, manifest3.origin, "provider is installed");
|
||||
let id = SocialMarks._toolbarHelper.idFromOrigin(provider.origin);
|
||||
let widget = CustomizableUI.getWidget(id);
|
||||
@ -134,7 +134,7 @@ var tests = {
|
||||
addTab(activationURL, function(tab) {
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
Social.installProvider(doc, manifest2, function(addonManifest) {
|
||||
SocialService.addBuiltinProvider(manifest2.origin, function(provider) {
|
||||
SocialService.enableProvider(manifest2.origin, function(provider) {
|
||||
is(provider.origin, manifest2.origin, "provider is installed");
|
||||
let id = SocialMarks._toolbarHelper.idFromOrigin(manifest2.origin);
|
||||
let widget = CustomizableUI.getWidget(id).forWindow(window)
|
||||
@ -334,7 +334,7 @@ var tests = {
|
||||
// enable the provider now
|
||||
let provider = Social._getProviderFromOrigin(manifest2.origin);
|
||||
ok(provider, "provider is installed");
|
||||
SocialService.removeProvider(manifest2.origin, function() {
|
||||
SocialService.disableProvider(manifest2.origin, function() {
|
||||
let id = SocialMarks._toolbarHelper.idFromOrigin(manifest2.origin);
|
||||
waitForCondition(function() {
|
||||
// getWidget now returns null since we've destroyed the widget
|
||||
@ -381,7 +381,7 @@ var tests = {
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
Social.installProvider(doc, manifest, function(addonManifest) {
|
||||
// enable the provider so we know the button would have appeared
|
||||
SocialService.addBuiltinProvider(manifest.origin, function(provider) {
|
||||
SocialService.enableProvider(manifest.origin, function(provider) {
|
||||
waitForCondition(function() { return CustomizableUI.getWidget(id) },
|
||||
function() {
|
||||
gBrowser.removeTab(tab);
|
||||
|
@ -70,7 +70,7 @@ function doTest() {
|
||||
checkShown(true);
|
||||
|
||||
// disable social.
|
||||
SocialService.removeProvider(SocialSidebar.provider.origin, function() {
|
||||
SocialService.disableProvider(SocialSidebar.provider.origin, function() {
|
||||
checkShown(false);
|
||||
is(Social.providers.length, 0, "no providers left");
|
||||
defaultFinishChecks();
|
||||
|
@ -68,7 +68,7 @@ var tests = {
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
Social.installProvider(doc, manifest3, function(addonManifest) {
|
||||
// enable the provider so we know the button would have appeared
|
||||
SocialService.addBuiltinProvider(manifest3.origin, function(provider) {
|
||||
SocialService.enableProvider(manifest3.origin, function(provider) {
|
||||
is(provider.origin, manifest3.origin, "provider is installed");
|
||||
let id = SocialStatus._toolbarHelper.idFromOrigin(provider.origin);
|
||||
let widget = CustomizableUI.getWidget(id);
|
||||
@ -94,7 +94,7 @@ var tests = {
|
||||
addTab(activationURL, function(tab) {
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
Social.installProvider(doc, manifest2, function(addonManifest) {
|
||||
SocialService.addBuiltinProvider(manifest2.origin, function(provider) {
|
||||
SocialService.enableProvider(manifest2.origin, function(provider) {
|
||||
is(provider.origin, manifest2.origin, "provider is installed");
|
||||
let id = SocialStatus._toolbarHelper.idFromOrigin(manifest2.origin);
|
||||
let widget = CustomizableUI.getWidget(id).forWindow(window);
|
||||
@ -156,7 +156,7 @@ var tests = {
|
||||
// enable the provider now
|
||||
let provider = Social._getProviderFromOrigin(manifest2.origin);
|
||||
ok(provider, "provider is installed");
|
||||
SocialService.removeProvider(manifest2.origin, function() {
|
||||
SocialService.disableProvider(manifest2.origin, function() {
|
||||
let id = SocialStatus._toolbarHelper.idFromOrigin(manifest2.origin);
|
||||
waitForCondition(function() { return !document.getElementById(id) },
|
||||
function() {
|
||||
|
@ -110,8 +110,8 @@ let tests = {
|
||||
checkSocialUI(w1);
|
||||
|
||||
// disable social and re-check
|
||||
SocialService.removeProvider(manifest.origin, function() {
|
||||
SocialService.removeProvider(manifest2.origin, function() {
|
||||
SocialService.disableProvider(manifest.origin, function() {
|
||||
SocialService.disableProvider(manifest2.origin, function() {
|
||||
ok(!Social.enabled, "social is disabled");
|
||||
is(Social.providers.length, 0, "no providers");
|
||||
ok(!w1.SocialSidebar.opened, "w1 sidebar is closed");
|
||||
@ -161,7 +161,7 @@ let tests = {
|
||||
ok(!Services.prefs.prefHasUserValue("social.sidebar.provider"), "4. global state unset");
|
||||
ok(!SocialSidebar.opened, "4. main sidebar is still closed");
|
||||
ok(!w1.SocialSidebar.opened, "4. window sidebar is closed");
|
||||
SocialService.removeProvider(manifest.origin, function() {
|
||||
SocialService.disableProvider(manifest.origin, function() {
|
||||
Services.prefs.clearUserPref("social.manifest.test");
|
||||
cbnext();
|
||||
});
|
||||
@ -180,8 +180,8 @@ let tests = {
|
||||
testPerWindowSidebar: function(cbnext) {
|
||||
function finishCheck() {
|
||||
// disable social and re-check
|
||||
SocialService.removeProvider(manifest.origin, function() {
|
||||
SocialService.removeProvider(manifest2.origin, function() {
|
||||
SocialService.disableProvider(manifest.origin, function() {
|
||||
SocialService.disableProvider(manifest2.origin, function() {
|
||||
ok(!Social.enabled, "social is disabled");
|
||||
is(Social.providers.length, 0, "no providers");
|
||||
Services.prefs.clearUserPref("social.manifest.test");
|
||||
|
@ -106,14 +106,14 @@ function runSocialTestWithProvider(manifest, callback, finishcallback) {
|
||||
// If we're "cleaning up", don't call finish when done.
|
||||
let callback = cleanup ? function () {} : finishIfDone;
|
||||
// Similarly, if we're cleaning up, catch exceptions from removeProvider
|
||||
let removeProvider = SocialService.removeProvider.bind(SocialService);
|
||||
let removeProvider = SocialService.disableProvider.bind(SocialService);
|
||||
if (cleanup) {
|
||||
removeProvider = function (origin, cb) {
|
||||
try {
|
||||
SocialService.removeProvider(origin, cb);
|
||||
SocialService.disableProvider(origin, cb);
|
||||
} catch (ex) {
|
||||
// Ignore "provider doesn't exist" errors.
|
||||
if (ex.message.indexOf("SocialService.removeProvider: no provider with origin") == 0)
|
||||
if (ex.message.indexOf("SocialService.disableProvider: no provider with origin") == 0)
|
||||
return;
|
||||
info("Failed to clean up provider " + origin + ": " + ex);
|
||||
}
|
||||
|
@ -72,6 +72,7 @@
|
||||
try {
|
||||
if (this._prefs.getBoolPref("unifiedcomplete")) {
|
||||
this.setAttribute("autocompletesearch", "unifiedcomplete");
|
||||
this.mSearchNames = null;
|
||||
}
|
||||
} catch (ex) {}
|
||||
|
||||
@ -612,6 +613,7 @@
|
||||
this.setAttribute("autocompletesearch",
|
||||
useUnifiedComplete ? "unifiedcomplete"
|
||||
: "urlinline history");
|
||||
this.mSearchNames = null;
|
||||
}
|
||||
}
|
||||
]]></body>
|
||||
|
@ -207,9 +207,10 @@ let UI = {
|
||||
setupBusyTimeout: function() {
|
||||
this.cancelBusyTimeout();
|
||||
this._busyTimeout = setTimeout(() => {
|
||||
let busyPromise = this._busyPromise;
|
||||
this.unbusy();
|
||||
UI.reportError("error_operationTimeout", this._busyOperationDescription);
|
||||
this._busyPromise.reject("promise timeout: " + this._busyOperationDescription);
|
||||
busyPromise.reject("promise timeout: " + this._busyOperationDescription);
|
||||
}, 30000);
|
||||
},
|
||||
|
||||
@ -810,8 +811,12 @@ let Cmds = {
|
||||
runtimeAppsNode.firstChild.remove();
|
||||
}
|
||||
|
||||
for (let i = 0; i < AppManager.webAppsStore.object.all.length; i++) {
|
||||
let app = AppManager.webAppsStore.object.all[i];
|
||||
let sortedApps = AppManager.webAppsStore.object.all;
|
||||
sortedApps = sortedApps.sort((a, b) => {
|
||||
return a.name > b.name;
|
||||
});
|
||||
for (let i = 0; i < sortedApps.length; i++) {
|
||||
let app = sortedApps[i];
|
||||
let panelItemNode = document.createElement("toolbarbutton");
|
||||
panelItemNode.className = "panel-item";
|
||||
panelItemNode.setAttribute("label", app.name);
|
||||
|
@ -4,7 +4,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
pref("devtools.webide.showProjectEditor", true);
|
||||
pref("devtools.webide.templatesURL", "http://code.cdn.mozilla.net/templates/list.json");
|
||||
pref("devtools.webide.templatesURL", "https://code.cdn.mozilla.net/templates/list.json");
|
||||
pref("devtools.webide.autoinstallADBHelper", true);
|
||||
pref("devtools.webide.lastprojectlocation", "");
|
||||
pref("devtools.webide.restoreLastProject", true);
|
||||
|
@ -1586,7 +1586,7 @@ Experiments.ExperimentEntry.prototype = {
|
||||
{ name: "endTime",
|
||||
condition: () => now < data.endTime },
|
||||
{ name: "maxStartTime",
|
||||
condition: () => !data.maxStartTime || now <= data.maxStartTime },
|
||||
condition: () => this._startDate || !data.maxStartTime || now <= data.maxStartTime },
|
||||
{ name: "maxActiveSeconds",
|
||||
condition: () => !this._startDate || now <= (startSec + maxActive) },
|
||||
{ name: "appName",
|
||||
|
@ -1539,6 +1539,66 @@ add_task(function* testEnabledAfterRestart() {
|
||||
yield testCleanup(experiments);
|
||||
});
|
||||
|
||||
// If experiment add-ons were ever started, maxStartTime shouldn't be evaluated
|
||||
// anymore. Ensure that if maxStartTime is passed but experiment has started
|
||||
// already, maxStartTime does not cause deactivation.
|
||||
|
||||
add_task(function* testMaxStartTimeEvaluation() {
|
||||
|
||||
// Dates the following tests are based on.
|
||||
|
||||
let startDate = new Date(2014, 5, 1, 12);
|
||||
let now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
|
||||
let maxStartDate = futureDate(startDate, 100 * MS_IN_ONE_DAY);
|
||||
let endDate = futureDate(startDate, 1000 * MS_IN_ONE_DAY);
|
||||
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
// The manifest data we test with.
|
||||
// We set a value for maxStartTime.
|
||||
|
||||
gManifestObject = {
|
||||
"version": 1,
|
||||
experiments: [
|
||||
{
|
||||
id: EXPERIMENT1_ID,
|
||||
xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
|
||||
xpiHash: EXPERIMENT1_XPI_SHA1,
|
||||
startTime: dateToSeconds(startDate),
|
||||
endTime: dateToSeconds(endDate),
|
||||
maxActiveSeconds: 1000 * SEC_IN_ONE_DAY,
|
||||
maxStartTime: dateToSeconds(maxStartDate),
|
||||
appName: ["XPCShell"],
|
||||
channel: ["nightly"],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
let experiments = new Experiments.Experiments(gPolicy);
|
||||
|
||||
let addons = yield getExperimentAddons();
|
||||
Assert.equal(addons.length, 0, "Precondition: No experiment add-ons installed.");
|
||||
|
||||
yield experiments.updateManifest();
|
||||
let fromManifest = yield experiments.getExperiments();
|
||||
Assert.equal(fromManifest.length, 1, "A single experiment is known.");
|
||||
|
||||
addons = yield getExperimentAddons();
|
||||
Assert.equal(addons.length, 1, "A single experiment add-on is installed.");
|
||||
Assert.ok(addons[0].isActive, "That experiment is active.");
|
||||
|
||||
dump("Setting current time to maxStartTime + 100 days and reloading manifest\n");
|
||||
now = futureDate(maxStartDate, 100 * MS_IN_ONE_DAY);
|
||||
defineNow(gPolicy, now);
|
||||
yield experiments.updateManifest();
|
||||
|
||||
addons = yield getExperimentAddons();
|
||||
Assert.equal(addons.length, 1, "The experiment is still there.");
|
||||
Assert.ok(addons[0].isActive, "It is still active.");
|
||||
|
||||
yield testCleanup(experiments);
|
||||
});
|
||||
|
||||
// Test coverage for an add-on uninstall disabling the experiment and that it stays
|
||||
// disabled over restarts.
|
||||
add_task(function* test_foreignUninstallAndRestart() {
|
||||
|
@ -112,6 +112,17 @@ crashedpluginsMessage.submitButton.label=Submit a crash report
|
||||
crashedpluginsMessage.submitButton.accesskey=S
|
||||
crashedpluginsMessage.learnMore=Learn More…
|
||||
|
||||
# Keyword fixup messages
|
||||
# LOCALIZATION NOTE (keywordURIFixup.message): Used when the user tries to visit
|
||||
# a local host page, by the time the DNS request recognizes it, we have already
|
||||
# loaded a search page for the given word. An infobar then asks to the user
|
||||
# whether he rather wanted to visit the host. %S is the recognized host.
|
||||
keywordURIFixup.message=Did you mean to go to %S?
|
||||
keywordURIFixup.goTo=Yes, take me to %S
|
||||
keywordURIFixup.goTo.accesskey=Y
|
||||
keywordURIFixup.dismiss=No thanks
|
||||
keywordURIFixup.dismiss.accesskey=N
|
||||
|
||||
## Plugin doorhanger strings
|
||||
# LOCALIZATION NOTE (pluginActivateNew.message): Used for newly-installed
|
||||
# plugins which are not known to be unsafe. %1$S is the plugin name and %2$S
|
||||
|
@ -252,6 +252,7 @@ pref("privacy.donottrackheader.value", -1);
|
||||
pref("dom.disable_window_open_dialog_feature", true);
|
||||
|
||||
pref("keyword.enabled", true);
|
||||
pref("browser.fixup.domainwhitelist.localhost", true);
|
||||
|
||||
pref("accessibility.typeaheadfind", false);
|
||||
pref("accessibility.typeaheadfind.timeout", 5000);
|
||||
|
@ -178,9 +178,9 @@ this.Social = {
|
||||
|
||||
// Activation functionality
|
||||
activateFromOrigin: function (origin, callback) {
|
||||
// For now only "builtin" providers can be activated. It's OK if the
|
||||
// provider has already been activated - we still get called back with it.
|
||||
SocialService.addBuiltinProvider(origin, callback);
|
||||
// It's OK if the provider has already been activated - we still get called
|
||||
// back with it.
|
||||
SocialService.enableProvider(origin, callback);
|
||||
},
|
||||
|
||||
// Page Marking functionality
|
||||
|
@ -20,13 +20,13 @@ function testStartupEnabled() {
|
||||
|
||||
function testDisableAfterStartup() {
|
||||
let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
|
||||
SocialService.removeProvider(Social.providers[0].origin, function() {
|
||||
SocialService.disableProvider(Social.providers[0].origin, function() {
|
||||
do_wait_observer("social:providers-changed", function() {
|
||||
do_check_eq(Social.enabled, false, "Social is disabled");
|
||||
do_check_eq(Social.providers.length, 0, "no social providers available");
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
SocialService.removeProvider(Social.providers[0].origin)
|
||||
SocialService.disableProvider(Social.providers[0].origin)
|
||||
});
|
||||
}
|
||||
|
@ -123,12 +123,25 @@ nsDefaultURIFixup::CreateExposableURI(nsIURI *aURI, nsIURI **aReturn)
|
||||
NS_IMETHODIMP
|
||||
nsDefaultURIFixup::CreateFixupURI(const nsACString& aStringURI, uint32_t aFixupFlags,
|
||||
nsIInputStream **aPostData, nsIURI **aURI)
|
||||
{
|
||||
nsCOMPtr<nsIURIFixupInfo> fixupInfo;
|
||||
nsresult rv = GetFixupURIInfo(aStringURI, aFixupFlags, aPostData,
|
||||
getter_AddRefs(fixupInfo));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
fixupInfo->GetPreferredURI(aURI);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDefaultURIFixup::GetFixupURIInfo(const nsACString& aStringURI, uint32_t aFixupFlags,
|
||||
nsIInputStream **aPostData, nsIURIFixupInfo **aInfo)
|
||||
{
|
||||
NS_ENSURE_ARG(!aStringURI.IsEmpty());
|
||||
NS_ENSURE_ARG_POINTER(aURI);
|
||||
|
||||
nsresult rv;
|
||||
*aURI = nullptr;
|
||||
nsRefPtr<nsDefaultURIFixupInfo> info = new nsDefaultURIFixupInfo(aStringURI);
|
||||
NS_ADDREF(*aInfo = info);
|
||||
|
||||
nsAutoCString uriString(aStringURI);
|
||||
uriString.Trim(" "); // Cleanup the empty spaces that might be on each end.
|
||||
@ -149,26 +162,35 @@ nsDefaultURIFixup::CreateFixupURI(const nsACString& aStringURI, uint32_t aFixupF
|
||||
|
||||
if (scheme.LowerCaseEqualsLiteral("view-source"))
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsCOMPtr<nsIURIFixupInfo> uriInfo;
|
||||
uint32_t newFixupFlags = aFixupFlags & ~FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
|
||||
|
||||
rv = CreateFixupURI(Substring(uriString,
|
||||
rv = GetFixupURIInfo(Substring(uriString,
|
||||
sizeof("view-source:") - 1,
|
||||
uriString.Length() -
|
||||
(sizeof("view-source:") - 1)),
|
||||
newFixupFlags, aPostData, getter_AddRefs(uri));
|
||||
newFixupFlags, aPostData, getter_AddRefs(uriInfo));
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE;
|
||||
nsAutoCString spec;
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
uriInfo->GetPreferredURI(getter_AddRefs(uri));
|
||||
if (!uri)
|
||||
return NS_ERROR_FAILURE;
|
||||
uri->GetSpec(spec);
|
||||
uriString.AssignLiteral("view-source:");
|
||||
uriString.Append(spec);
|
||||
}
|
||||
else {
|
||||
// Check for if it is a file URL
|
||||
FileURIFixup(uriString, aURI);
|
||||
if(*aURI)
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
FileURIFixup(uriString, getter_AddRefs(uri));
|
||||
if (uri)
|
||||
{
|
||||
uri.swap(info->mFixedURI);
|
||||
info->mPreferredURI = info->mFixedURI;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// Not a file URL, so translate '\' to '/' for convenience in the common protocols
|
||||
@ -223,6 +245,8 @@ nsDefaultURIFixup::CreateFixupURI(const nsACString& aStringURI, uint32_t aFixupF
|
||||
sInitializedPrefCaches = true;
|
||||
}
|
||||
|
||||
info->mInputHasProtocol = !scheme.IsEmpty();
|
||||
|
||||
// Fix up common scheme typos.
|
||||
if (sFixTypos && (aFixupFlags & FIXUP_FLAG_FIX_SCHEME_TYPOS)) {
|
||||
|
||||
@ -266,17 +290,25 @@ nsDefaultURIFixup::CreateFixupURI(const nsACString& aStringURI, uint32_t aFixupF
|
||||
|
||||
ioService->GetProtocolHandler(scheme.get(), getter_AddRefs(ourHandler));
|
||||
extHandler = do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"default");
|
||||
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
if (ourHandler != extHandler || !PossiblyHostPortUrl(uriString)) {
|
||||
// Just try to create an URL out of it
|
||||
rv = NS_NewURI(aURI, uriString, nullptr);
|
||||
rv = NS_NewURI(getter_AddRefs(uri), uriString, nullptr);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
info->mFixedURI = uri;
|
||||
// Figure out whether this had a domain or just a single hostname:
|
||||
nsAutoCString host;
|
||||
uri->GetHost(host);
|
||||
info->mInputHostHasDot = host.FindChar('.') != kNotFound;
|
||||
}
|
||||
|
||||
if (!*aURI && rv != NS_ERROR_MALFORMED_URI) {
|
||||
if (!uri && rv != NS_ERROR_MALFORMED_URI) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
if (*aURI && ourHandler == extHandler && sFixupKeywords &&
|
||||
if (uri && ourHandler == extHandler && sFixupKeywords &&
|
||||
(aFixupFlags & FIXUP_FLAG_FIX_SCHEME_TYPOS)) {
|
||||
nsCOMPtr<nsIExternalProtocolService> extProtService =
|
||||
do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
|
||||
@ -291,85 +323,64 @@ nsDefaultURIFixup::CreateFixupURI(const nsACString& aStringURI, uint32_t aFixupF
|
||||
// It's more likely the user wants to search, and so we
|
||||
// chuck this over to their preferred search provider instead:
|
||||
if (!handlerExists) {
|
||||
NS_RELEASE(*aURI);
|
||||
KeywordToURI(uriString, aPostData, aURI);
|
||||
nsresult rv = KeywordToURI(uriString, aPostData, getter_AddRefs(uri));
|
||||
if (NS_SUCCEEDED(rv) && uri) {
|
||||
info->mFixupUsedKeyword = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*aURI) {
|
||||
if (uri) {
|
||||
if (aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI)
|
||||
MakeAlternateURI(*aURI);
|
||||
MakeAlternateURI(uri);
|
||||
info->mPreferredURI = uri;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Fix up protocol string before calling KeywordURIFixup, because
|
||||
// it cares about the hostname of such URIs:
|
||||
nsCOMPtr<nsIURI> uriWithProtocol;
|
||||
// NB: this rv gets returned at the end of this method if we never
|
||||
// do a keyword fixup after this (because the pref or the flags passed
|
||||
// might not let us).
|
||||
rv = FixupURIProtocol(uriString, getter_AddRefs(uriWithProtocol));
|
||||
if (uriWithProtocol) {
|
||||
info->mFixedURI = uriWithProtocol;
|
||||
nsAutoCString host;
|
||||
uriWithProtocol->GetHost(host);
|
||||
info->mInputHostHasDot = host.FindChar('.') != kNotFound;
|
||||
}
|
||||
|
||||
// See if it is a keyword
|
||||
// Test whether keywords need to be fixed up
|
||||
if (sFixupKeywords && (aFixupFlags & FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP)) {
|
||||
KeywordURIFixup(uriString, aPostData, aURI);
|
||||
if(*aURI)
|
||||
KeywordURIFixup(uriString, info, aPostData);
|
||||
if (info->mPreferredURI)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Prune duff protocol schemes
|
||||
//
|
||||
// ://totallybroken.url.com
|
||||
// //shorthand.url.com
|
||||
//
|
||||
if (StringBeginsWith(uriString, NS_LITERAL_CSTRING("://")))
|
||||
{
|
||||
uriString = StringTail(uriString, uriString.Length() - 3);
|
||||
}
|
||||
else if (StringBeginsWith(uriString, NS_LITERAL_CSTRING("//")))
|
||||
{
|
||||
uriString = StringTail(uriString, uriString.Length() - 2);
|
||||
}
|
||||
|
||||
// Add ftp:// or http:// to front of url if it has no spec
|
||||
//
|
||||
// Should fix:
|
||||
//
|
||||
// no-scheme.com
|
||||
// ftp.no-scheme.com
|
||||
// ftp4.no-scheme.com
|
||||
// no-scheme.com/query?foo=http://www.foo.com
|
||||
//
|
||||
int32_t schemeDelim = uriString.Find("://",0);
|
||||
int32_t firstDelim = uriString.FindCharInSet("/:");
|
||||
if (schemeDelim <= 0 ||
|
||||
(firstDelim != -1 && schemeDelim > firstDelim)) {
|
||||
// find host name
|
||||
int32_t hostPos = uriString.FindCharInSet("/:?#");
|
||||
if (hostPos == -1)
|
||||
hostPos = uriString.Length();
|
||||
|
||||
// extract host name
|
||||
nsAutoCString hostSpec;
|
||||
uriString.Left(hostSpec, hostPos);
|
||||
|
||||
// insert url spec corresponding to host name
|
||||
if (IsLikelyFTP(hostSpec))
|
||||
uriString.InsertLiteral("ftp://", 0);
|
||||
else
|
||||
uriString.InsertLiteral("http://", 0);
|
||||
} // end if checkprotocol
|
||||
|
||||
rv = NS_NewURI(aURI, uriString, nullptr);
|
||||
|
||||
// Did the caller want us to try an alternative URI?
|
||||
// If so, attempt to fixup http://foo into http://www.foo.com
|
||||
|
||||
if (*aURI && aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI) {
|
||||
MakeAlternateURI(*aURI);
|
||||
if (info->mFixedURI && aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI) {
|
||||
MakeAlternateURI(info->mFixedURI);
|
||||
}
|
||||
|
||||
// If we still haven't been able to construct a valid URI, try to force a
|
||||
// keyword match. This catches search strings with '.' or ':' in them.
|
||||
if (!*aURI && sFixupKeywords)
|
||||
if (info->mFixedURI)
|
||||
{
|
||||
KeywordToURI(aStringURI, aPostData, aURI);
|
||||
if(*aURI)
|
||||
info->mPreferredURI = info->mFixedURI;
|
||||
}
|
||||
else if (sFixupKeywords && (aFixupFlags & FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP))
|
||||
{
|
||||
rv = KeywordToURI(aStringURI, aPostData, getter_AddRefs(info->mPreferredURI));
|
||||
if (NS_SUCCEEDED(rv) && info->mPreferredURI)
|
||||
{
|
||||
info->mFixupUsedKeyword = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
@ -708,6 +719,61 @@ nsresult nsDefaultURIFixup::ConvertFileToStringURI(const nsACString& aIn,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDefaultURIFixup::FixupURIProtocol(const nsACString & aURIString,
|
||||
nsIURI** aURI)
|
||||
{
|
||||
nsAutoCString uriString(aURIString);
|
||||
*aURI = nullptr;
|
||||
|
||||
// Prune duff protocol schemes
|
||||
//
|
||||
// ://totallybroken.url.com
|
||||
// //shorthand.url.com
|
||||
//
|
||||
if (StringBeginsWith(uriString, NS_LITERAL_CSTRING("://")))
|
||||
{
|
||||
uriString = StringTail(uriString, uriString.Length() - 3);
|
||||
}
|
||||
else if (StringBeginsWith(uriString, NS_LITERAL_CSTRING("//")))
|
||||
{
|
||||
uriString = StringTail(uriString, uriString.Length() - 2);
|
||||
}
|
||||
|
||||
// Add ftp:// or http:// to front of url if it has no spec
|
||||
//
|
||||
// Should fix:
|
||||
//
|
||||
// no-scheme.com
|
||||
// ftp.no-scheme.com
|
||||
// ftp4.no-scheme.com
|
||||
// no-scheme.com/query?foo=http://www.foo.com
|
||||
//
|
||||
int32_t schemeDelim = uriString.Find("://",0);
|
||||
int32_t firstDelim = uriString.FindCharInSet("/:");
|
||||
if (schemeDelim <= 0 ||
|
||||
(firstDelim != -1 && schemeDelim > firstDelim)) {
|
||||
// find host name
|
||||
int32_t hostPos = uriString.FindCharInSet("/:?#");
|
||||
if (hostPos == -1)
|
||||
hostPos = uriString.Length();
|
||||
|
||||
// extract host name
|
||||
nsAutoCString hostSpec;
|
||||
uriString.Left(hostSpec, hostPos);
|
||||
|
||||
// insert url spec corresponding to host name
|
||||
if (IsLikelyFTP(hostSpec))
|
||||
uriString.InsertLiteral("ftp://", 0);
|
||||
else
|
||||
uriString.InsertLiteral("http://", 0);
|
||||
} // end if checkprotocol
|
||||
|
||||
return NS_NewURI(aURI, uriString, nullptr);
|
||||
}
|
||||
|
||||
|
||||
bool nsDefaultURIFixup::PossiblyHostPortUrl(const nsACString &aUrl)
|
||||
{
|
||||
// Oh dear, the protocol is invalid. Test if the protocol might
|
||||
@ -830,8 +896,8 @@ bool nsDefaultURIFixup::PossiblyByteExpandedFileName(const nsAString& aIn)
|
||||
}
|
||||
|
||||
void nsDefaultURIFixup::KeywordURIFixup(const nsACString & aURIString,
|
||||
nsIInputStream **aPostData,
|
||||
nsIURI** aURI)
|
||||
nsDefaultURIFixupInfo* aFixupInfo,
|
||||
nsIInputStream **aPostData)
|
||||
{
|
||||
// These are keyword formatted strings
|
||||
// "what is mozilla"
|
||||
@ -840,6 +906,7 @@ void nsDefaultURIFixup::KeywordURIFixup(const nsACString & aURIString,
|
||||
// "?mozilla" - anything that begins with a question mark
|
||||
// "?site:mozilla.org docshell"
|
||||
// Things that have a quote before the first dot/colon
|
||||
// "mozilla" - checked against a whitelist to see if it's a host or not
|
||||
|
||||
// These are not keyword formatted strings
|
||||
// "www.blah.com" - first space-separated substring contains a dot, doesn't start with "?"
|
||||
@ -865,16 +932,46 @@ void nsDefaultURIFixup::KeywordURIFixup(const nsACString & aURIString,
|
||||
uint32_t quoteLoc = std::min(uint32_t(aURIString.FindChar('"')),
|
||||
uint32_t(aURIString.FindChar('\'')));
|
||||
|
||||
nsresult rv;
|
||||
if (((spaceLoc < dotLoc || quoteLoc < dotLoc) &&
|
||||
(spaceLoc < colonLoc || quoteLoc < colonLoc) &&
|
||||
(spaceLoc < qMarkLoc || quoteLoc < qMarkLoc)) ||
|
||||
qMarkLoc == 0)
|
||||
{
|
||||
KeywordToURI(aURIString, aPostData, aURI);
|
||||
rv = KeywordToURI(aURIString, aPostData,
|
||||
getter_AddRefs(aFixupInfo->mPreferredURI));
|
||||
if (NS_SUCCEEDED(rv) && aFixupInfo->mPreferredURI)
|
||||
{
|
||||
aFixupInfo->mFixupUsedKeyword = true;
|
||||
}
|
||||
}
|
||||
else if (dotLoc == uint32_t(kNotFound) && colonLoc == uint32_t(kNotFound) &&
|
||||
qMarkLoc == uint32_t(kNotFound))
|
||||
{
|
||||
nsAutoCString asciiHost;
|
||||
if (NS_SUCCEEDED(aFixupInfo->mFixedURI->GetAsciiHost(asciiHost)) &&
|
||||
!asciiHost.IsEmpty())
|
||||
{
|
||||
// Check if this domain is whitelisted as an actual
|
||||
// domain (which will prevent a keyword query)
|
||||
nsAutoCString pref("browser.fixup.domainwhitelist.");
|
||||
pref.Append(asciiHost);
|
||||
if (Preferences::GetBool(pref.get(), false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If we get here, we don't have a valid URI, or we did but the
|
||||
// host is not whitelisted, so we do a keyword search *anyway*:
|
||||
rv = KeywordToURI(aURIString, aPostData,
|
||||
getter_AddRefs(aFixupInfo->mPreferredURI));
|
||||
if (NS_SUCCEEDED(rv) && aFixupInfo->mPreferredURI)
|
||||
{
|
||||
aFixupInfo->mFixupUsedKeyword = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsresult NS_NewURIFixup(nsIURIFixup **aURIFixup)
|
||||
{
|
||||
nsDefaultURIFixup *fixup = new nsDefaultURIFixup;
|
||||
@ -885,3 +982,78 @@ nsresult NS_NewURIFixup(nsIURIFixup **aURIFixup)
|
||||
return fixup->QueryInterface(NS_GET_IID(nsIURIFixup), (void **) aURIFixup);
|
||||
}
|
||||
|
||||
|
||||
/* Implementation of nsIURIFixupInfo */
|
||||
NS_IMPL_ISUPPORTS(nsDefaultURIFixupInfo, nsIURIFixupInfo)
|
||||
|
||||
nsDefaultURIFixupInfo::nsDefaultURIFixupInfo(const nsACString& aOriginalInput):
|
||||
mFixupUsedKeyword(false),
|
||||
mInputHasProtocol(false),
|
||||
mInputHostHasDot(false)
|
||||
{
|
||||
mOriginalInput = aOriginalInput;
|
||||
}
|
||||
|
||||
|
||||
nsDefaultURIFixupInfo::~nsDefaultURIFixupInfo()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDefaultURIFixupInfo::GetConsumer(nsISupports** aConsumer)
|
||||
{
|
||||
*aConsumer = mConsumer;
|
||||
NS_IF_ADDREF(*aConsumer);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDefaultURIFixupInfo::SetConsumer(nsISupports* aConsumer)
|
||||
{
|
||||
mConsumer = aConsumer;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDefaultURIFixupInfo::GetPreferredURI(nsIURI** aPreferredURI)
|
||||
{
|
||||
*aPreferredURI = mPreferredURI;
|
||||
NS_IF_ADDREF(*aPreferredURI);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDefaultURIFixupInfo::GetFixedURI(nsIURI** aFixedURI)
|
||||
{
|
||||
*aFixedURI = mFixedURI;
|
||||
NS_IF_ADDREF(*aFixedURI);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDefaultURIFixupInfo::GetFixupUsedKeyword(bool* aOut)
|
||||
{
|
||||
*aOut = mFixupUsedKeyword;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDefaultURIFixupInfo::GetInputHasProtocol(bool* aOut)
|
||||
{
|
||||
*aOut = mInputHasProtocol;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDefaultURIFixupInfo::GetInputHostHasDot(bool* aOut)
|
||||
{
|
||||
*aOut = mInputHostHasDot;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDefaultURIFixupInfo::GetOriginalInput(nsACString& aInput)
|
||||
{
|
||||
aInput = mOriginalInput;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
#include "nsIURIFixup.h"
|
||||
|
||||
class nsDefaultURIFixupInfo;
|
||||
|
||||
/* Header file */
|
||||
class nsDefaultURIFixup : public nsIURIFixup
|
||||
{
|
||||
@ -25,11 +27,36 @@ private:
|
||||
/* additional members */
|
||||
nsresult FileURIFixup(const nsACString &aStringURI, nsIURI** aURI);
|
||||
nsresult ConvertFileToStringURI(const nsACString& aIn, nsCString& aOut);
|
||||
void KeywordURIFixup(const nsACString &aStringURI, nsIInputStream** aPostData, nsIURI** aURI);
|
||||
nsresult FixupURIProtocol(const nsACString& aIn, nsIURI** aURI);
|
||||
void KeywordURIFixup(const nsACString &aStringURI,
|
||||
nsDefaultURIFixupInfo* aFixupInfo,
|
||||
nsIInputStream** aPostData);
|
||||
bool PossiblyByteExpandedFileName(const nsAString& aIn);
|
||||
bool PossiblyHostPortUrl(const nsACString& aUrl);
|
||||
bool MakeAlternateURI(nsIURI *aURI);
|
||||
bool IsLikelyFTP(const nsCString& aHostSpec);
|
||||
};
|
||||
|
||||
class nsDefaultURIFixupInfo : public nsIURIFixupInfo
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIURIFIXUPINFO
|
||||
|
||||
nsDefaultURIFixupInfo(const nsACString& aOriginalInput);
|
||||
|
||||
friend class nsDefaultURIFixup;
|
||||
|
||||
protected:
|
||||
virtual ~nsDefaultURIFixupInfo();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsISupports> mConsumer;
|
||||
nsCOMPtr<nsIURI> mPreferredURI;
|
||||
nsCOMPtr<nsIURI> mFixedURI;
|
||||
bool mFixupUsedKeyword;
|
||||
bool mInputHasProtocol;
|
||||
bool mInputHostHasDot;
|
||||
nsAutoCString mOriginalInput;
|
||||
};
|
||||
#endif
|
||||
|
@ -4362,15 +4362,29 @@ nsDocShell::LoadURIWithBase(const char16_t * aURI,
|
||||
fixupFlags |= nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS;
|
||||
}
|
||||
nsCOMPtr<nsIInputStream> fixupStream;
|
||||
rv = sURIFixup->CreateFixupURI(uriString, fixupFlags,
|
||||
getter_AddRefs(fixupStream),
|
||||
getter_AddRefs(uri));
|
||||
nsCOMPtr<nsIURIFixupInfo> fixupInfo;
|
||||
rv = sURIFixup->GetFixupURIInfo(uriString, fixupFlags,
|
||||
getter_AddRefs(fixupStream),
|
||||
getter_AddRefs(fixupInfo));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
fixupInfo->GetPreferredURI(getter_AddRefs(uri));
|
||||
fixupInfo->SetConsumer(GetAsSupports(this));
|
||||
}
|
||||
|
||||
if (fixupStream) {
|
||||
// CreateFixupURI only returns a post data stream if it succeeded
|
||||
// and changed the URI, in which case we should override the
|
||||
// passed-in post data.
|
||||
postStream = fixupStream;
|
||||
}
|
||||
|
||||
if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
|
||||
nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
|
||||
if (serv) {
|
||||
serv->NotifyObservers(fixupInfo, "keyword-uri-fixup", aURI);
|
||||
}
|
||||
}
|
||||
}
|
||||
// else no fixup service so just use the URI we created and see
|
||||
// what happens
|
||||
|
@ -9,10 +9,61 @@
|
||||
interface nsIURI;
|
||||
interface nsIInputStream;
|
||||
|
||||
/**
|
||||
* Interface indicating what we found/corrected when fixing up a URI
|
||||
*/
|
||||
[scriptable, uuid(c9b6cc32-c24e-4283-adaa-9290577fd609)]
|
||||
interface nsIURIFixupInfo : nsISupports
|
||||
{
|
||||
/**
|
||||
* Consumer that asked for fixed up URI.
|
||||
*/
|
||||
attribute nsISupports consumer;
|
||||
|
||||
/**
|
||||
* Our best guess as to what URI the consumer will want. Might
|
||||
* be null if we couldn't salvage anything (for instance, because
|
||||
* the input was invalid as a URI and FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP
|
||||
* was not passed)
|
||||
*/
|
||||
readonly attribute nsIURI preferredURI;
|
||||
|
||||
/**
|
||||
* The fixed-up original input, *never* using a keyword search.
|
||||
* (might be null if the original input was not recoverable as
|
||||
* a URL, e.g. "foo bar"!)
|
||||
*/
|
||||
readonly attribute nsIURI fixedURI;
|
||||
|
||||
/**
|
||||
* Whether the preferred option ended up using a keyword search.
|
||||
*/
|
||||
readonly attribute boolean fixupUsedKeyword;
|
||||
|
||||
/**
|
||||
* Whether we think there was a protocol specified in some way,
|
||||
* even if we corrected it (e.g. "ttp://foo.com/bar")
|
||||
*/
|
||||
readonly attribute boolean inputHasProtocol;
|
||||
|
||||
/**
|
||||
* Whether the input included a dot in the hostname, e.g. "mozilla.org"
|
||||
* rather than just "mozilla". This makes a difference in terms of when we
|
||||
* decide to do a keyword search or not.
|
||||
*/
|
||||
readonly attribute boolean inputHostHasDot;
|
||||
|
||||
/**
|
||||
* The original input
|
||||
*/
|
||||
readonly attribute AUTF8String originalInput;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Interface implemented by objects capable of fixing up strings into URIs
|
||||
*/
|
||||
[scriptable, uuid(731877f8-973b-414c-b772-9ca1f3fffb7e)]
|
||||
[scriptable, uuid(80d4932e-bb2e-4afb-98e0-de9cc9ea7d82)]
|
||||
interface nsIURIFixup : nsISupports
|
||||
{
|
||||
/** No fixup flags. */
|
||||
@ -63,6 +114,20 @@ interface nsIURIFixup : nsISupports
|
||||
nsIURI createFixupURI(in AUTF8String aURIText, in unsigned long aFixupFlags,
|
||||
[optional] out nsIInputStream aPostData);
|
||||
|
||||
/**
|
||||
* Same as createFixupURI, but returns information about what it corrected
|
||||
* (e.g. whether we could rescue the URI or "just" generated a keyword
|
||||
* search URI instead).
|
||||
*
|
||||
* @param aURIText Candidate URI.
|
||||
* @param aFixupFlags Flags that govern ways the URI may be fixed up.
|
||||
* @param aPostData The POST data to submit with the returned
|
||||
* URI (see nsISearchSubmission).
|
||||
*/
|
||||
nsIURIFixupInfo getFixupURIInfo(in AUTF8String aURIText,
|
||||
in unsigned long aFixupFlags,
|
||||
[optional] out nsIInputStream aPostData);
|
||||
|
||||
/**
|
||||
* Converts the specified keyword string into a URI. Note that it's the
|
||||
* caller's responsibility to check whether keywords are enabled and
|
||||
|
147
docshell/test/unit/test_nsDefaultURIFixup_info.js
Normal file
147
docshell/test/unit/test_nsDefaultURIFixup_info.js
Normal file
@ -0,0 +1,147 @@
|
||||
let urifixup = Cc["@mozilla.org/docshell/urifixup;1"].
|
||||
getService(Ci.nsIURIFixup);
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
let prefList = ["browser.fixup.typo.scheme", "keyword.enabled"];
|
||||
for (let pref of prefList) {
|
||||
Services.prefs.setBoolPref(pref, true);
|
||||
}
|
||||
|
||||
const kSearchEngineID = "test_urifixup_search_engine";
|
||||
const kSearchEngineURL = "http://www.example.org/?search={searchTerms}";
|
||||
Services.search.addEngineWithDetails(kSearchEngineID, "", "", "", "get",
|
||||
kSearchEngineURL);
|
||||
|
||||
let oldDefaultEngine = Services.search.defaultEngine;
|
||||
Services.search.defaultEngine = Services.search.getEngineByName(kSearchEngineID);
|
||||
|
||||
let selectedName = Services.search.defaultEngine.name;
|
||||
do_check_eq(selectedName, kSearchEngineID);
|
||||
|
||||
do_register_cleanup(function() {
|
||||
if (oldDefaultEngine) {
|
||||
Services.search.defaultEngine = oldDefaultEngine;
|
||||
}
|
||||
let engine = Services.search.getEngineByName(kSearchEngineID);
|
||||
if (engine) {
|
||||
Services.search.removeEngine(engine);
|
||||
}
|
||||
Services.prefs.clearUserPref("keyword.enabled");
|
||||
Services.prefs.clearUserPref("browser.fixup.typo.scheme");
|
||||
});
|
||||
|
||||
let flagInputs = [
|
||||
urifixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP,
|
||||
urifixup.FIXUP_FLAGS_MAKE_ALTERNATE_URI,
|
||||
urifixup.FIXUP_FLAG_FIX_SCHEME_TYPOS
|
||||
];
|
||||
|
||||
flagInputs.concat([
|
||||
flagInputs[0] | flagInputs[1],
|
||||
flagInputs[1] | flagInputs[2],
|
||||
flagInputs[0] | flagInputs[2],
|
||||
flagInputs[0] | flagInputs[1] | flagInputs[2]
|
||||
]);
|
||||
|
||||
let testcases = [
|
||||
["http://www.mozilla.org", "http://www.mozilla.org/"],
|
||||
["://www.mozilla.org", "http://www.mozilla.org/"],
|
||||
["www.mozilla.org", "http://www.mozilla.org/"],
|
||||
["http://mozilla/", "http://mozilla/"],
|
||||
["127.0.0.1", "http://127.0.0.1/"],
|
||||
["1234", "http://1234/"],
|
||||
["host/foo.txt", "http://host/foo.txt"],
|
||||
["mozilla", "http://mozilla/"],
|
||||
["mozilla is amazing", null],
|
||||
["", null],
|
||||
];
|
||||
|
||||
if (Services.appinfo.OS.toLowerCase().startsWith("win")) {
|
||||
testcases.push(["C:\\some\\file.txt", "file:///C:/some/file.txt"]);
|
||||
} else {
|
||||
testcases.push(["/some/file.txt", "file:///some/file.txt"]);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
for (let [testInput, expectedFixedURI] of testcases) {
|
||||
for (let flags of flagInputs) {
|
||||
let info;
|
||||
let fixupURIOnly = null;
|
||||
try {
|
||||
fixupURIOnly = urifixup.createFixupURI(testInput, flags);
|
||||
} catch (ex) {
|
||||
do_check_eq(expectedFixedURI, null);
|
||||
}
|
||||
|
||||
try {
|
||||
info = urifixup.getFixupURIInfo(testInput, flags);
|
||||
} catch (ex) {
|
||||
// Both APIs should return an error in the same cases.
|
||||
do_check_eq(expectedFixedURI, null);
|
||||
do_check_eq(fixupURIOnly, null);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Both APIs should then also be using the same spec.
|
||||
do_check_eq(fixupURIOnly.spec, info.preferredURI.spec);
|
||||
|
||||
let isFileURL = expectedFixedURI && expectedFixedURI.startsWith("file");
|
||||
|
||||
// Check the fixedURI:
|
||||
let alternateURI = flags & urifixup.FIXUP_FLAGS_MAKE_ALTERNATE_URI;
|
||||
if (!isFileURL && alternateURI && !info.inputHostHasDot && info.fixedURI) {
|
||||
let originalURI = Services.io.newURI(expectedFixedURI, null, null);
|
||||
do_check_eq(info.fixedURI.host, "www." + originalURI.host + ".com");
|
||||
} else {
|
||||
do_check_eq(info.fixedURI && info.fixedURI.spec, expectedFixedURI);
|
||||
}
|
||||
|
||||
// Check booleans on input:
|
||||
if (isFileURL) {
|
||||
do_check_eq(info.inputHasProtocol, testInput.startsWith("file:"));
|
||||
do_check_eq(info.inputHostHasDot, false);
|
||||
} else {
|
||||
// The duff protocol doesn't count, so > 0 rather than -1:
|
||||
do_check_eq(info.inputHasProtocol, testInput.indexOf(":") > 0);
|
||||
let dotIndex = testInput.indexOf(".");
|
||||
let slashIndex = testInput.replace("://", "").indexOf("/");
|
||||
slashIndex = slashIndex == -1 ? testInput.length : slashIndex;
|
||||
do_check_eq(info.inputHostHasDot, dotIndex != -1 && slashIndex > dotIndex);
|
||||
}
|
||||
|
||||
let couldDoKeywordLookup = flags & urifixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
|
||||
// Check the preferred URI
|
||||
if (info.inputHostHasDot || info.inputHasProtocol) {
|
||||
// In these cases, we should never be doing a keyword lookup and
|
||||
// the fixed URI should be preferred:
|
||||
do_check_eq(info.preferredURI.spec, info.fixedURI.spec);
|
||||
} else if (!isFileURL && couldDoKeywordLookup && testInput.indexOf(".") == -1) {
|
||||
// Otherwise, and assuming we're allowed, there will be a search URI:
|
||||
let urlparamInput = testInput.replace(/ /g, '+');
|
||||
let searchURL = kSearchEngineURL.replace("{searchTerms}", urlparamInput);
|
||||
do_check_eq(info.preferredURI.spec, searchURL);
|
||||
} else if (info.fixedURI) {
|
||||
// This is for lack of keyword lookup, combined with hostnames with no
|
||||
// protocol:
|
||||
do_check_eq(info.fixedURI, info.preferredURI);
|
||||
if (isFileURL) {
|
||||
do_check_eq(info.fixedURI.host, "");
|
||||
} else {
|
||||
let hostMatch = testInput.match(/(?:[^:\/]*:\/\/)?([^\/]+)(\/|$)/);
|
||||
let host = hostMatch ? hostMatch[1] : "";
|
||||
if (alternateURI) {
|
||||
do_check_eq(info.fixedURI.host, "www." + host + ".com");
|
||||
} else {
|
||||
do_check_eq(info.fixedURI.host, host);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
do_check_true(false, "There should be no cases where we got here, " +
|
||||
"there's no keyword lookup, and no fixed URI." +
|
||||
"Offending input: " + testInput);
|
||||
}
|
||||
do_check_eq(testInput, info.originalInput);
|
||||
}
|
||||
}
|
||||
}
|
@ -7,6 +7,8 @@ tail =
|
||||
[test_nsDefaultURIFixup.js]
|
||||
[test_nsDefaultURIFixup_search.js]
|
||||
skip-if = os == 'android'
|
||||
[test_nsDefaultURIFixup_info.js]
|
||||
skip-if = os == 'android'
|
||||
[test_nsIDownloadHistory.js]
|
||||
[test_pb_notification.js]
|
||||
# Bug 751575: unrelated JS changes cause timeouts on random platforms
|
||||
|
@ -230,6 +230,7 @@ pref("dom.disable_window_print", true);
|
||||
pref("dom.disable_window_find", true);
|
||||
|
||||
pref("keyword.enabled", true);
|
||||
pref("browser.fixup.domainwhitelist.localhost", true);
|
||||
|
||||
pref("accessibility.typeaheadfind", false);
|
||||
pref("accessibility.typeaheadfind.timeout", 5000);
|
||||
|
@ -106,7 +106,13 @@
|
||||
android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation|screenSize|locale|layoutDirection"
|
||||
android:windowSoftInputMode="stateUnspecified|adjustResize"
|
||||
android:launchMode="singleTask"
|
||||
android:exported="true"
|
||||
android:theme="@style/Gecko.App">
|
||||
<!-- We export this activity so that it can be launched by explicit
|
||||
intents, in particular homescreen shortcuts. See Bug 1032217.
|
||||
In future we would prefer to move all intent filters off the .App
|
||||
alias and onto BrowserApp so that we can deprecate activities
|
||||
that refer to pre-processed class names. -->
|
||||
</activity>
|
||||
|
||||
<!-- Fennec is shipped as the Android package named
|
||||
@ -255,10 +261,16 @@
|
||||
android:taskAffinity="org.mozilla.gecko.WEBAPP"
|
||||
android:process=":@ANDROID_PACKAGE_NAME@.Webapp"
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="true"
|
||||
android:theme="@style/Gecko.App">
|
||||
<!-- We export this activity so that it can be launched by explicit
|
||||
intents, in particular old-style WebApp launching homescreen
|
||||
shortcuts. Such shortcuts were made before the new "synthetic
|
||||
APK" WebApps were deployed. See Bug 1032217. -->
|
||||
</activity>
|
||||
|
||||
<!-- Alias Webapp so we can launch it from the package namespace. -->
|
||||
<!-- Alias Webapp so we can launch it from the package namespace. Prefer
|
||||
to launch with the fully qualified name "org.mozilla.gecko.Webapp". -->
|
||||
<activity-alias android:name=".Webapp"
|
||||
android:label="@string/webapp_generic_name"
|
||||
android:targetActivity="org.mozilla.gecko.Webapp">
|
||||
|
@ -5,18 +5,13 @@
|
||||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
@ -81,8 +76,6 @@ import android.hardware.SensorEventListener;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.net.Uri;
|
||||
import android.net.wifi.ScanResult;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@ -90,12 +83,6 @@ import android.os.PowerManager;
|
||||
import android.os.StrictMode;
|
||||
import android.provider.ContactsContract;
|
||||
import android.provider.MediaStore.Images.Media;
|
||||
import android.telephony.CellLocation;
|
||||
import android.telephony.NeighboringCellInfo;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.telephony.SignalStrength;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.telephony.gsm.GsmCellLocation;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Base64;
|
||||
@ -165,8 +152,6 @@ public abstract class GeckoApp
|
||||
public static final String SAVED_STATE_IN_BACKGROUND = "inBackground";
|
||||
public static final String SAVED_STATE_PRIVATE_SESSION = "privateSession";
|
||||
|
||||
static private final String LOCATION_URL = "https://location.services.mozilla.com/v1/submit";
|
||||
|
||||
// Delay before running one-time "cleanup" tasks that may be needed
|
||||
// after a version upgrade.
|
||||
private static final int CLEANUP_DEFERRAL_SECONDS = 15;
|
||||
@ -207,9 +192,6 @@ public abstract class GeckoApp
|
||||
private volatile HealthRecorder mHealthRecorder = null;
|
||||
private volatile Locale mLastLocale = null;
|
||||
|
||||
private int mSignalStrenth;
|
||||
private PhoneStateListener mPhoneStateListener = null;
|
||||
private boolean mShouldReportGeoData;
|
||||
private EventListener mWebappEventListener;
|
||||
|
||||
abstract public int getLayout();
|
||||
@ -249,15 +231,6 @@ public abstract class GeckoApp
|
||||
}
|
||||
|
||||
public LocationListener getLocationListener() {
|
||||
if (mShouldReportGeoData && mPhoneStateListener == null) {
|
||||
mPhoneStateListener = new PhoneStateListener() {
|
||||
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
|
||||
setCurrentSignalStrenth(signalStrength);
|
||||
}
|
||||
};
|
||||
TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
|
||||
tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -1578,10 +1551,7 @@ public abstract class GeckoApp
|
||||
|
||||
PrefsHelper.getPref("app.geo.reportdata", new PrefsHelper.PrefHandlerBase() {
|
||||
@Override public void prefValue(String pref, int value) {
|
||||
if (value == 1)
|
||||
mShouldReportGeoData = true;
|
||||
else
|
||||
mShouldReportGeoData = false;
|
||||
// Acting on this pref is Bug 1036508; for now, do nothing.
|
||||
}
|
||||
});
|
||||
|
||||
@ -2373,197 +2343,6 @@ public abstract class GeckoApp
|
||||
public void onLocationChanged(Location location) {
|
||||
// No logging here: user-identifying information.
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createLocationEvent(location));
|
||||
if (mShouldReportGeoData)
|
||||
collectAndReportLocInfo(location);
|
||||
}
|
||||
|
||||
public void setCurrentSignalStrenth(SignalStrength ss) {
|
||||
if (ss.isGsm())
|
||||
mSignalStrenth = ss.getGsmSignalStrength();
|
||||
}
|
||||
|
||||
private int getCellInfo(JSONArray cellInfo) {
|
||||
TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
|
||||
if (tm == null)
|
||||
return TelephonyManager.PHONE_TYPE_NONE;
|
||||
List<NeighboringCellInfo> cells = tm.getNeighboringCellInfo();
|
||||
CellLocation cl = tm.getCellLocation();
|
||||
String mcc = "", mnc = "";
|
||||
if (cl instanceof GsmCellLocation) {
|
||||
JSONObject obj = new JSONObject();
|
||||
GsmCellLocation gcl = (GsmCellLocation)cl;
|
||||
try {
|
||||
obj.put("lac", gcl.getLac());
|
||||
obj.put("cid", gcl.getCid());
|
||||
|
||||
int psc = (Build.VERSION.SDK_INT >= 9) ? gcl.getPsc() : -1;
|
||||
obj.put("psc", psc);
|
||||
|
||||
switch(tm.getNetworkType()) {
|
||||
case TelephonyManager.NETWORK_TYPE_GPRS:
|
||||
case TelephonyManager.NETWORK_TYPE_EDGE:
|
||||
obj.put("radio", "gsm");
|
||||
break;
|
||||
case TelephonyManager.NETWORK_TYPE_UMTS:
|
||||
case TelephonyManager.NETWORK_TYPE_HSDPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSUPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSPAP:
|
||||
obj.put("radio", "umts");
|
||||
break;
|
||||
}
|
||||
String mcc_mnc = tm.getNetworkOperator();
|
||||
if (mcc_mnc.length() > 3) {
|
||||
mcc = mcc_mnc.substring(0, 3);
|
||||
mnc = mcc_mnc.substring(3);
|
||||
obj.put("mcc", mcc);
|
||||
obj.put("mnc", mnc);
|
||||
}
|
||||
obj.put("asu", mSignalStrenth);
|
||||
} catch(JSONException jsonex) {}
|
||||
cellInfo.put(obj);
|
||||
}
|
||||
if (cells != null) {
|
||||
for (NeighboringCellInfo nci : cells) {
|
||||
try {
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("lac", nci.getLac());
|
||||
obj.put("cid", nci.getCid());
|
||||
obj.put("psc", nci.getPsc());
|
||||
obj.put("mcc", mcc);
|
||||
obj.put("mnc", mnc);
|
||||
|
||||
int dbm;
|
||||
switch(nci.getNetworkType()) {
|
||||
case TelephonyManager.NETWORK_TYPE_GPRS:
|
||||
case TelephonyManager.NETWORK_TYPE_EDGE:
|
||||
obj.put("radio", "gsm");
|
||||
break;
|
||||
case TelephonyManager.NETWORK_TYPE_UMTS:
|
||||
case TelephonyManager.NETWORK_TYPE_HSDPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSUPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSPAP:
|
||||
obj.put("radio", "umts");
|
||||
break;
|
||||
}
|
||||
|
||||
obj.put("asu", nci.getRssi());
|
||||
cellInfo.put(obj);
|
||||
} catch(JSONException jsonex) {}
|
||||
}
|
||||
}
|
||||
return tm.getPhoneType();
|
||||
}
|
||||
|
||||
private static boolean shouldLog(final ScanResult sr) {
|
||||
return sr.SSID == null || !sr.SSID.endsWith("_nomap");
|
||||
}
|
||||
|
||||
private void collectAndReportLocInfo(Location location) {
|
||||
final JSONObject locInfo = new JSONObject();
|
||||
WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
|
||||
wm.startScan();
|
||||
try {
|
||||
JSONArray cellInfo = new JSONArray();
|
||||
|
||||
String radioType = getRadioTypeName(getCellInfo(cellInfo));
|
||||
if (radioType != null) {
|
||||
locInfo.put("radio", radioType);
|
||||
}
|
||||
|
||||
locInfo.put("lon", location.getLongitude());
|
||||
locInfo.put("lat", location.getLatitude());
|
||||
|
||||
// If we have an accuracy, round it up to the next meter.
|
||||
if (location.hasAccuracy()) {
|
||||
locInfo.put("accuracy", (int) Math.ceil(location.getAccuracy()));
|
||||
}
|
||||
|
||||
// If we have an altitude, round it to the nearest meter.
|
||||
if (location.hasAltitude()) {
|
||||
locInfo.put("altitude", Math.round(location.getAltitude()));
|
||||
}
|
||||
|
||||
// Reduce timestamp precision so as to expose less PII.
|
||||
DateFormat df = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
|
||||
locInfo.put("time", df.format(new Date(location.getTime())));
|
||||
locInfo.put("cell", cellInfo);
|
||||
|
||||
JSONArray wifiInfo = new JSONArray();
|
||||
List<ScanResult> aps = wm.getScanResults();
|
||||
if (aps != null) {
|
||||
for (ScanResult ap : aps) {
|
||||
if (!shouldLog(ap))
|
||||
continue;
|
||||
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("key", ap.BSSID);
|
||||
obj.put("frequency", ap.frequency);
|
||||
obj.put("signal", ap.level);
|
||||
wifiInfo.put(obj);
|
||||
}
|
||||
}
|
||||
locInfo.put("wifi", wifiInfo);
|
||||
} catch (JSONException jsonex) {
|
||||
Log.w(LOGTAG, "json exception", jsonex);
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
URL url = new URL(LOCATION_URL);
|
||||
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
|
||||
try {
|
||||
urlConnection.setDoOutput(true);
|
||||
|
||||
// Workaround for a bug in Android HttpURLConnection. When the library
|
||||
// reuses a stale connection, the connection may fail with an EOFException.
|
||||
if (Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT <= 18) {
|
||||
urlConnection.setRequestProperty("Connection", "Close");
|
||||
}
|
||||
|
||||
JSONArray batch = new JSONArray();
|
||||
batch.put(locInfo);
|
||||
JSONObject wrapper = new JSONObject();
|
||||
wrapper.put("items", batch);
|
||||
byte[] bytes = wrapper.toString().getBytes();
|
||||
urlConnection.setFixedLengthStreamingMode(bytes.length);
|
||||
OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
|
||||
out.write(bytes);
|
||||
out.flush();
|
||||
} catch (JSONException jsonex) {
|
||||
Log.e(LOGTAG, "error wrapping data as a batch", jsonex);
|
||||
} catch (IOException ioex) {
|
||||
Log.e(LOGTAG, "error submitting data", ioex);
|
||||
} finally {
|
||||
urlConnection.disconnect();
|
||||
}
|
||||
} catch (IOException ioex) {
|
||||
Log.e(LOGTAG, "error submitting data", ioex);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static String getRadioTypeName(int phoneType) {
|
||||
switch (phoneType) {
|
||||
case TelephonyManager.PHONE_TYPE_CDMA:
|
||||
return "cdma";
|
||||
|
||||
case TelephonyManager.PHONE_TYPE_GSM:
|
||||
return "gsm";
|
||||
|
||||
case TelephonyManager.PHONE_TYPE_NONE:
|
||||
case TelephonyManager.PHONE_TYPE_SIP:
|
||||
// These devices have no radio.
|
||||
return null;
|
||||
|
||||
default:
|
||||
Log.e(LOGTAG, "", new IllegalArgumentException("Unexpected PHONE_TYPE: " + phoneType));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1524,8 +1524,8 @@ var BrowserApp = {
|
||||
let url = data.url;
|
||||
let flags;
|
||||
|
||||
if (!data.engine && /^[0-9]+$/.test(url)) {
|
||||
// If the query is a number and we're not using a search engine,
|
||||
if (!data.engine && /^\w+$/.test(url.trim())) {
|
||||
// If the query is a single word and we're not using a search engine,
|
||||
// force a search (see bug 993705; workaround for bug 693808).
|
||||
url = URIFixup.keywordToURI(url).spec;
|
||||
} else {
|
||||
|
@ -20,8 +20,6 @@ public class Constants {
|
||||
public static final String PRESEARCH_FRAGMENT = "org.mozilla.search.PRESEARCH_FRAGMENT";
|
||||
public static final String SEARCH_FRAGMENT = "org.mozilla.search.SEARCH_FRAGMENT";
|
||||
|
||||
public static final String AUTOCOMPLETE_ROW_LIMIT = "5";
|
||||
|
||||
public static final String YAHOO_WEB_SEARCH_BASE_URL = "https://search.yahoo.com/search?p=";
|
||||
public static final String YAHOO_WEB_SEARCH_RESULTS_FILTER = "//search.yahoo.com";
|
||||
}
|
||||
|
@ -9,10 +9,12 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The adapter that is used to populate the autocomplete rows.
|
||||
*/
|
||||
class AutoCompleteAdapter extends ArrayAdapter<AutoCompleteModel> {
|
||||
class AutoCompleteAdapter extends ArrayAdapter<String> {
|
||||
|
||||
private final AcceptsJumpTaps acceptsJumpTaps;
|
||||
|
||||
@ -21,6 +23,9 @@ class AutoCompleteAdapter extends ArrayAdapter<AutoCompleteModel> {
|
||||
// and supplying our own view.
|
||||
super(context, 0);
|
||||
this.acceptsJumpTaps = acceptsJumpTaps;
|
||||
|
||||
// Disable notifying on change. We will notify ourselves in update.
|
||||
setNotifyOnChange(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -34,12 +39,23 @@ class AutoCompleteAdapter extends ArrayAdapter<AutoCompleteModel> {
|
||||
}
|
||||
|
||||
view.setOnJumpListener(acceptsJumpTaps);
|
||||
|
||||
|
||||
AutoCompleteModel model = getItem(position);
|
||||
|
||||
view.setMainText(model.getMainText());
|
||||
view.setMainText(getItem(position));
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates adapter content with new list of search suggestions.
|
||||
*
|
||||
* @param suggestions List of search suggestions.
|
||||
*/
|
||||
public void update(List<String> suggestions) {
|
||||
clear();
|
||||
if (suggestions != null) {
|
||||
for (String s : suggestions) {
|
||||
add(s);
|
||||
}
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
@ -1,84 +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/. */
|
||||
|
||||
package org.mozilla.search.autocomplete;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.database.Cursor;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A single entry point for querying all agents.
|
||||
* <p/>
|
||||
* An agent is responsible for querying some underlying data source. It could be a
|
||||
* flat file, or a REST endpoint, or a content provider.
|
||||
*/
|
||||
class AutoCompleteAgentManager {
|
||||
|
||||
private final Handler mainUiHandler;
|
||||
private final Handler localHandler;
|
||||
private final AutoCompleteWordListAgent autoCompleteWordListAgent;
|
||||
|
||||
public AutoCompleteAgentManager(Activity activity, Handler mainUiHandler) {
|
||||
HandlerThread thread = new HandlerThread("org.mozilla.search.autocomplete.SuggestionAgent");
|
||||
// TODO: Where to kill this thread?
|
||||
thread.start();
|
||||
Log.i("AUTOCOMPLETE", "Starting thread");
|
||||
this.mainUiHandler = mainUiHandler;
|
||||
localHandler = new SuggestionMessageHandler(thread.getLooper());
|
||||
autoCompleteWordListAgent = new AutoCompleteWordListAgent(activity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the next incoming query.
|
||||
*/
|
||||
public void search(String queryString) {
|
||||
// TODO check if there's a pending search.. not sure how to handle that.
|
||||
localHandler.sendMessage(localHandler.obtainMessage(0, queryString));
|
||||
}
|
||||
|
||||
/**
|
||||
* This background thread runs the queries; the results get sent back through mainUiHandler
|
||||
* <p/>
|
||||
* TODO: Refactor this wordlist search and add other search providers (eg: Yahoo)
|
||||
*/
|
||||
private class SuggestionMessageHandler extends Handler {
|
||||
|
||||
private SuggestionMessageHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
super.handleMessage(msg);
|
||||
if (null == msg.obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
Cursor cursor =
|
||||
autoCompleteWordListAgent.getWordMatches(((String) msg.obj).toLowerCase());
|
||||
ArrayList<AutoCompleteModel> res = new ArrayList<AutoCompleteModel>();
|
||||
|
||||
if (null == cursor) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
|
||||
res.add(new AutoCompleteModel(cursor.getString(
|
||||
cursor.getColumnIndex(AutoCompleteWordListAgent.COL_WORD))));
|
||||
}
|
||||
|
||||
|
||||
mainUiHandler.sendMessage(Message.obtain(mainUiHandler, 0, res));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,31 +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/. */
|
||||
|
||||
package org.mozilla.search.autocomplete;
|
||||
|
||||
/**
|
||||
* The SuggestionModel is the data model behind the autocomplete rows. Right now it
|
||||
* only has a text field. In the future, this could be extended to include other
|
||||
* types of rows. For example, a row that has a URL and the name of a website.
|
||||
*/
|
||||
class AutoCompleteModel {
|
||||
|
||||
// The text that should immediately jump out to the user;
|
||||
// for example, the name of a restaurant or the title
|
||||
// of a website.
|
||||
private final String mainText;
|
||||
|
||||
public AutoCompleteModel(String mainText) {
|
||||
this.mainText = mainText;
|
||||
}
|
||||
|
||||
public String getMainText() {
|
||||
return mainText;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return mainText;
|
||||
}
|
||||
|
||||
}
|
@ -1,153 +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/. */
|
||||
|
||||
package org.mozilla.search.autocomplete;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.database.sqlite.SQLiteQueryBuilder;
|
||||
import android.database.sqlite.SQLiteStatement;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.mozilla.search.Constants;
|
||||
import org.mozilla.search.R;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
/**
|
||||
* Helper to search a word dictionary.
|
||||
* From: https://developer.android.com/training/search/search.html
|
||||
*/
|
||||
class AutoCompleteWordListAgent {
|
||||
|
||||
public static final String COL_WORD = "WORD";
|
||||
private static final String TAG = "DictionaryDatabase";
|
||||
private static final String DATABASE_NAME = "DICTIONARY";
|
||||
private static final String FTS_VIRTUAL_TABLE = "FTS";
|
||||
private static final int DATABASE_VERSION = 1;
|
||||
|
||||
private final DatabaseOpenHelper databaseOpenHelper;
|
||||
|
||||
public AutoCompleteWordListAgent(Activity activity) {
|
||||
databaseOpenHelper = new DatabaseOpenHelper(activity);
|
||||
// DB helper uses lazy initialization, so this forces the db helper to start indexing the
|
||||
// wordlist
|
||||
databaseOpenHelper.getReadableDatabase();
|
||||
}
|
||||
|
||||
public Cursor getWordMatches(String query) {
|
||||
String selection = COL_WORD + " MATCH ?";
|
||||
String[] selectionArgs = new String[]{query + "*"};
|
||||
return query(selection, selectionArgs);
|
||||
}
|
||||
|
||||
private Cursor query(String selection, String[] selectionArgs) {
|
||||
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
|
||||
builder.setTables(FTS_VIRTUAL_TABLE);
|
||||
|
||||
Cursor cursor = builder.query(databaseOpenHelper.getReadableDatabase(), null, selection,
|
||||
selectionArgs, null, null, null, Constants.AUTOCOMPLETE_ROW_LIMIT);
|
||||
|
||||
if (cursor == null) {
|
||||
return null;
|
||||
} else if (!cursor.moveToFirst()) {
|
||||
cursor.close();
|
||||
return null;
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
private static class DatabaseOpenHelper extends SQLiteOpenHelper {
|
||||
|
||||
private final Activity activity;
|
||||
|
||||
private SQLiteDatabase database;
|
||||
|
||||
private static final String FTS_TABLE_CREATE =
|
||||
"CREATE VIRTUAL TABLE " + FTS_VIRTUAL_TABLE + " USING fts3 (" + COL_WORD + ")";
|
||||
|
||||
DatabaseOpenHelper(Activity activity) {
|
||||
super(activity, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
database = db;
|
||||
database.execSQL(FTS_TABLE_CREATE);
|
||||
|
||||
loadDictionary();
|
||||
}
|
||||
|
||||
private void loadDictionary() {
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(activity, "Starting post-install indexing",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(activity,
|
||||
"Don't worry; Mark & Ian we'll figure out a way around " +
|
||||
"this :)", Toast.LENGTH_SHORT
|
||||
).show();
|
||||
}
|
||||
});
|
||||
loadWords();
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(activity, "All done!", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void loadWords() throws IOException {
|
||||
final Resources resources = activity.getResources();
|
||||
InputStream inputStream = resources.openRawResource(R.raw.en_us);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
|
||||
|
||||
String sql = "INSERT INTO " + FTS_VIRTUAL_TABLE + " VALUES (?);";
|
||||
SQLiteStatement statement = database.compileStatement(sql);
|
||||
database.beginTransaction();
|
||||
|
||||
try {
|
||||
String line;
|
||||
while (null != (line = reader.readLine())) {
|
||||
statement.clearBindings();
|
||||
statement.bindString(1, line.trim());
|
||||
statement.execute();
|
||||
}
|
||||
} finally {
|
||||
database.setTransactionSuccessful();
|
||||
database.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion +
|
||||
", which will destroy all old data");
|
||||
db.execSQL("DROP TABLE IF EXISTS " + FTS_VIRTUAL_TABLE);
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -7,9 +7,10 @@ package org.mozilla.search.autocomplete;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.KeyEvent;
|
||||
@ -27,22 +28,37 @@ import android.widget.TextView;
|
||||
|
||||
import org.mozilla.search.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A fragment to handle autocomplete. Its interface with the outside
|
||||
* world should be very very limited.
|
||||
* <p/>
|
||||
* TODO: Add more search providers (other than the dictionary)
|
||||
*/
|
||||
public class SearchFragment extends Fragment implements AdapterView.OnItemClickListener,
|
||||
TextView.OnEditorActionListener, AcceptsJumpTaps {
|
||||
public class SearchFragment extends Fragment
|
||||
implements TextView.OnEditorActionListener, AcceptsJumpTaps {
|
||||
|
||||
private static final int LOADER_ID_SUGGESTION = 0;
|
||||
private static final String KEY_SEARCH_TERM = "search_term";
|
||||
|
||||
// Timeout for the suggestion client to respond
|
||||
private static final int SUGGESTION_TIMEOUT = 3000;
|
||||
|
||||
// Maximum number of results returned by the suggestion client
|
||||
private static final int SUGGESTION_MAX = 5;
|
||||
|
||||
private View mainView;
|
||||
private FrameLayout backdropFrame;
|
||||
private EditText searchBar;
|
||||
private ListView suggestionDropdown;
|
||||
private InputMethodManager inputMethodManager;
|
||||
|
||||
private AutoCompleteAdapter autoCompleteAdapter;
|
||||
private AutoCompleteAgentManager autoCompleteAgentManager;
|
||||
|
||||
private SuggestClient suggestClient;
|
||||
private SuggestionLoaderCallbacks suggestionLoaderCallbacks;
|
||||
|
||||
private State state;
|
||||
|
||||
private enum State {
|
||||
@ -58,7 +74,6 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
|
||||
mainView = inflater.inflate(R.layout.search_auto_complete, container, false);
|
||||
backdropFrame = (FrameLayout) mainView.findViewById(R.id.auto_complete_backdrop);
|
||||
searchBar = (EditText) mainView.findViewById(R.id.auto_complete_search_bar);
|
||||
@ -71,17 +86,17 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL
|
||||
searchBar.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
autoCompleteAgentManager.search(s.toString());
|
||||
final Bundle args = new Bundle();
|
||||
args.putString(KEY_SEARCH_TERM, s.toString());
|
||||
getLoaderManager().restartLoader(LOADER_ID_SUGGESTION, args, suggestionLoaderCallbacks);
|
||||
}
|
||||
});
|
||||
searchBar.setOnEditorActionListener(this);
|
||||
@ -106,18 +121,8 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL
|
||||
backdropFrame.setOnClickListener(new BackdropClickListener());
|
||||
|
||||
autoCompleteAdapter = new AutoCompleteAdapter(getActivity(), this);
|
||||
|
||||
// Disable notifying on change. We're going to be changing the entire dataset, so
|
||||
// we don't want multiple re-draws.
|
||||
autoCompleteAdapter.setNotifyOnChange(false);
|
||||
|
||||
suggestionDropdown.setAdapter(autoCompleteAdapter);
|
||||
|
||||
initRows();
|
||||
|
||||
autoCompleteAgentManager =
|
||||
new AutoCompleteAgentManager(getActivity(), new MainUiHandler(autoCompleteAdapter));
|
||||
|
||||
// This will hide the autocomplete box and background frame.
|
||||
transitionToWaiting();
|
||||
|
||||
@ -125,12 +130,18 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL
|
||||
suggestionDropdown.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
String query = ((AutoCompleteModel) suggestionDropdown.getItemAtPosition(position))
|
||||
.getMainText();
|
||||
String query = (String) suggestionDropdown.getItemAtPosition(position);
|
||||
startSearch(query);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: Don't hard-code this template string (bug 1039758)
|
||||
final String template = "https://search.yahoo.com/sugg/ff?" +
|
||||
"output=fxjson&appid=ffm&command=__searchTerms__&nresults=" + SUGGESTION_MAX;
|
||||
|
||||
suggestClient = new SuggestClient(getActivity(), template, SUGGESTION_TIMEOUT, SUGGESTION_MAX);
|
||||
suggestionLoaderCallbacks = new SuggestionLoaderCallbacks();
|
||||
|
||||
return mainView;
|
||||
}
|
||||
|
||||
@ -146,15 +157,8 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL
|
||||
suggestionDropdown = null;
|
||||
}
|
||||
autoCompleteAdapter = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for clicks of individual items.
|
||||
*/
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
// TODO: Right now each row has its own click handler.
|
||||
// Can we
|
||||
suggestClient = null;
|
||||
suggestionLoaderCallbacks = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -169,18 +173,6 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private void initRows() {
|
||||
// TODO: Query history for these items.
|
||||
autoCompleteAdapter.add(new AutoCompleteModel("banana"));
|
||||
autoCompleteAdapter.add(new AutoCompleteModel("cat pics"));
|
||||
autoCompleteAdapter.add(new AutoCompleteModel("mexican food"));
|
||||
autoCompleteAdapter.add(new AutoCompleteModel("cuba libre"));
|
||||
|
||||
autoCompleteAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a search intent and put the widget into waiting.
|
||||
*/
|
||||
@ -226,41 +218,78 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL
|
||||
searchBar.setText(suggestion);
|
||||
// Move cursor to end of search input.
|
||||
searchBar.setSelection(suggestion.length());
|
||||
autoCompleteAgentManager.search(suggestion);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Receives messages from the SuggestionAgent's background thread.
|
||||
*/
|
||||
private static class MainUiHandler extends Handler {
|
||||
|
||||
final AutoCompleteAdapter autoCompleteAdapter1;
|
||||
|
||||
public MainUiHandler(AutoCompleteAdapter autoCompleteAdapter) {
|
||||
autoCompleteAdapter1 = autoCompleteAdapter;
|
||||
private class SuggestionLoaderCallbacks implements LoaderManager.LoaderCallbacks<List<String>> {
|
||||
@Override
|
||||
public Loader<List<String>> onCreateLoader(int id, Bundle args) {
|
||||
// suggestClient is set to null in onDestroyView(), so using it
|
||||
// safely here relies on the fact that onCreateLoader() is called
|
||||
// synchronously in restartLoader().
|
||||
return new SuggestionAsyncLoader(getActivity(), suggestClient, args.getString(KEY_SEARCH_TERM));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
super.handleMessage(msg);
|
||||
if (null == msg.obj) {
|
||||
return;
|
||||
public void onLoadFinished(Loader<List<String>> loader, List<String> suggestions) {
|
||||
autoCompleteAdapter.update(suggestions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<List<String>> loader) {
|
||||
if (autoCompleteAdapter != null) {
|
||||
autoCompleteAdapter.update(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class SuggestionAsyncLoader extends AsyncTaskLoader<List<String>> {
|
||||
private final SuggestClient suggestClient;
|
||||
private final String searchTerm;
|
||||
private List<String> suggestions;
|
||||
|
||||
public SuggestionAsyncLoader(Context context, SuggestClient suggestClient, String searchTerm) {
|
||||
super(context);
|
||||
this.suggestClient = suggestClient;
|
||||
this.searchTerm = searchTerm;
|
||||
this.suggestions = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> loadInBackground() {
|
||||
return suggestClient.query(searchTerm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliverResult(List<String> suggestions) {
|
||||
this.suggestions = suggestions;
|
||||
|
||||
if (isStarted()) {
|
||||
super.deliverResult(suggestions);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
if (suggestions != null) {
|
||||
deliverResult(suggestions);
|
||||
}
|
||||
|
||||
if (!(msg.obj instanceof Iterable)) {
|
||||
return;
|
||||
if (takeContentChanged() || suggestions == null) {
|
||||
forceLoad();
|
||||
}
|
||||
}
|
||||
|
||||
autoCompleteAdapter1.clear();
|
||||
@Override
|
||||
protected void onStopLoading() {
|
||||
cancelLoad();
|
||||
}
|
||||
|
||||
for (Object obj : (Iterable) msg.obj) {
|
||||
if (obj instanceof AutoCompleteModel) {
|
||||
autoCompleteAdapter1.add((AutoCompleteModel) obj);
|
||||
}
|
||||
}
|
||||
autoCompleteAdapter1.notifyDataSetChanged();
|
||||
@Override
|
||||
protected void onReset() {
|
||||
super.onReset();
|
||||
|
||||
onStopLoading();
|
||||
suggestions = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,145 @@
|
||||
/* 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/. */
|
||||
|
||||
package org.mozilla.search.autocomplete;
|
||||
|
||||
import org.json.JSONArray;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Use network-based search suggestions.
|
||||
*/
|
||||
public class SuggestClient {
|
||||
private static final String LOGTAG = "GeckoSuggestClient";
|
||||
private static final String USER_AGENT = "";
|
||||
|
||||
private final Context mContext;
|
||||
private final int mTimeout;
|
||||
|
||||
// should contain the string "__searchTerms__", which is replaced with the query
|
||||
private final String mSuggestTemplate;
|
||||
|
||||
// the maximum number of suggestions to return
|
||||
private final int mMaxResults;
|
||||
|
||||
// used by robocop for testing
|
||||
private boolean mCheckNetwork;
|
||||
|
||||
// used to make suggestions appear instantly after opt-in
|
||||
private String mPrevQuery;
|
||||
private ArrayList<String> mPrevResults;
|
||||
|
||||
public SuggestClient(Context context, String suggestTemplate, int timeout, int maxResults) {
|
||||
mContext = context;
|
||||
mMaxResults = maxResults;
|
||||
mSuggestTemplate = suggestTemplate;
|
||||
mTimeout = timeout;
|
||||
mCheckNetwork = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries for a given search term and returns an ArrayList of suggestions.
|
||||
*/
|
||||
public ArrayList<String> query(String query) {
|
||||
if (query.equals(mPrevQuery))
|
||||
return mPrevResults;
|
||||
|
||||
ArrayList<String> suggestions = new ArrayList<String>();
|
||||
if (TextUtils.isEmpty(mSuggestTemplate) || TextUtils.isEmpty(query)) {
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
if (!isNetworkConnected() && mCheckNetwork) {
|
||||
Log.i(LOGTAG, "Not connected to network");
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
try {
|
||||
String encoded = URLEncoder.encode(query, "UTF-8");
|
||||
String suggestUri = mSuggestTemplate.replace("__searchTerms__", encoded);
|
||||
|
||||
URL url = new URL(suggestUri);
|
||||
String json = null;
|
||||
HttpURLConnection urlConnection = null;
|
||||
InputStream in = null;
|
||||
try {
|
||||
urlConnection = (HttpURLConnection) url.openConnection();
|
||||
urlConnection.setConnectTimeout(mTimeout);
|
||||
urlConnection.setRequestProperty("User-Agent", USER_AGENT);
|
||||
in = new BufferedInputStream(urlConnection.getInputStream());
|
||||
json = convertStreamToString(in);
|
||||
} finally {
|
||||
if (urlConnection != null)
|
||||
urlConnection.disconnect();
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(LOGTAG, "error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (json != null) {
|
||||
/*
|
||||
* Sample result:
|
||||
* ["foo",["food network","foothill college","foot locker",...]]
|
||||
*/
|
||||
JSONArray results = new JSONArray(json);
|
||||
JSONArray jsonSuggestions = results.getJSONArray(1);
|
||||
|
||||
int added = 0;
|
||||
for (int i = 0; (i < jsonSuggestions.length()) && (added < mMaxResults); i++) {
|
||||
String suggestion = jsonSuggestions.getString(i);
|
||||
if (!suggestion.equalsIgnoreCase(query)) {
|
||||
suggestions.add(suggestion);
|
||||
added++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.e(LOGTAG, "Suggestion query failed");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Error", e);
|
||||
}
|
||||
|
||||
mPrevQuery = query;
|
||||
mPrevResults = suggestions;
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
private boolean isNetworkConnected() {
|
||||
NetworkInfo networkInfo = getActiveNetworkInfo();
|
||||
return networkInfo != null && networkInfo.isConnected();
|
||||
}
|
||||
|
||||
private NetworkInfo getActiveNetworkInfo() {
|
||||
ConnectivityManager connectivity = (ConnectivityManager) mContext
|
||||
.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
if (connectivity == null)
|
||||
return null;
|
||||
return connectivity.getActiveNetworkInfo();
|
||||
}
|
||||
|
||||
private String convertStreamToString(java.io.InputStream is) {
|
||||
try {
|
||||
return new java.util.Scanner(is).useDelimiter("\\A").next();
|
||||
} catch (java.util.NoSuchElementException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -8,11 +8,9 @@ search_activity_sources = [
|
||||
'java/org/mozilla/search/autocomplete/AcceptsJumpTaps.java',
|
||||
'java/org/mozilla/search/autocomplete/AcceptsSearchQuery.java',
|
||||
'java/org/mozilla/search/autocomplete/AutoCompleteAdapter.java',
|
||||
'java/org/mozilla/search/autocomplete/AutoCompleteAgentManager.java',
|
||||
'java/org/mozilla/search/autocomplete/AutoCompleteModel.java',
|
||||
'java/org/mozilla/search/autocomplete/AutoCompleteRowView.java',
|
||||
'java/org/mozilla/search/autocomplete/AutoCompleteWordListAgent.java',
|
||||
'java/org/mozilla/search/autocomplete/SearchFragment.java',
|
||||
'java/org/mozilla/search/autocomplete/SuggestClient.java',
|
||||
'java/org/mozilla/search/Constants.java',
|
||||
'java/org/mozilla/search/MainActivity.java',
|
||||
'java/org/mozilla/search/PostSearchFragment.java',
|
||||
|
@ -4062,10 +4062,9 @@ pref("memory.dump_reports_on_oom", false);
|
||||
// Number of stack frames to capture in createObjectURL for about:memory.
|
||||
pref("memory.blob_report.stack_frames", 0);
|
||||
|
||||
// comma separated list of domain origins (e.g. https://domain.com) for
|
||||
// providers that can install from their own website without user warnings.
|
||||
// entries are
|
||||
pref("social.whitelist", "https://mozsocial.cliqz.com,https://now.msn.com,https://mixi.jp");
|
||||
// comma separated list of domain origins (e.g. https://domain.com) that still
|
||||
// need localStorage in the frameworker
|
||||
pref("social.whitelist", "https://mozsocial.cliqz.com");
|
||||
// comma separated list of domain origins (e.g. https://domain.com) for
|
||||
// directory websites (e.g. AMO) that can install providers for other sites
|
||||
pref("social.directories", "https://activations.cdn.mozilla.net");
|
||||
|
@ -19,7 +19,7 @@ const TOPIC_PREFCHANGED = "nsPref:changed";
|
||||
|
||||
const DEFAULT_BEHAVIOR = 0;
|
||||
|
||||
const PREF_BRANCH = "browser.urlbar";
|
||||
const PREF_BRANCH = "browser.urlbar.";
|
||||
|
||||
// Prefs are defined as [pref name, default value].
|
||||
const PREF_ENABLED = [ "autocomplete.enabled", true ];
|
||||
@ -91,7 +91,7 @@ const SQL_BOOKMARK_TAGS_FRAGMENT = sql(
|
||||
"( SELECT title FROM moz_bookmarks WHERE fk = h.id AND title NOTNULL",
|
||||
"ORDER BY lastModified DESC LIMIT 1",
|
||||
") AS btitle,",
|
||||
"( SELECT GROUP_CONCAT(t.title, ',')",
|
||||
"( SELECT GROUP_CONCAT(t.title, ', ')",
|
||||
"FROM moz_bookmarks b",
|
||||
"JOIN moz_bookmarks t ON t.id = +b.parent AND t.parent = :parent",
|
||||
"WHERE b.fk = h.id",
|
||||
@ -187,7 +187,7 @@ const SQL_KEYWORD_QUERY = sql(
|
||||
|
||||
const SQL_HOST_QUERY = sql(
|
||||
"/* do not warn (bug NA): not worth to index on (typed, frecency) */",
|
||||
"SELECT :query_type, host || '/', prefix || host || '/',",
|
||||
"SELECT :query_type, host || '/', IFNULL(prefix, '') || host || '/',",
|
||||
"NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, frecency",
|
||||
"FROM moz_hosts",
|
||||
"WHERE host BETWEEN :searchString AND :searchString || X'FFFF'",
|
||||
@ -200,7 +200,7 @@ const SQL_TYPED_HOST_QUERY = SQL_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,",
|
||||
"SELECT :query_type, h.url, NULL,",
|
||||
"NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, h.frecency",
|
||||
"FROM moz_places h",
|
||||
"WHERE h.frecency <> 0",
|
||||
@ -434,41 +434,62 @@ function stripPrefix(spec)
|
||||
return spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip http and trailing separators from a spec.
|
||||
*
|
||||
* @param spec
|
||||
* The text to modify.
|
||||
* @return the modified spec.
|
||||
*/
|
||||
function stripHttpAndTrim(spec) {
|
||||
if (spec.startsWith("http://")) {
|
||||
spec = spec.slice(7);
|
||||
}
|
||||
if (spec.endsWith("?")) {
|
||||
spec = spec.slice(0, -1);
|
||||
}
|
||||
if (spec.endsWith("/")) {
|
||||
spec = spec.slice(0, -1);
|
||||
}
|
||||
return spec;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Search Class
|
||||
//// Manages a single instance of an autocomplete search.
|
||||
|
||||
function Search(searchString, searchParam, autocompleteListener,
|
||||
resultListener, autocompleteSearch) {
|
||||
// We want to store the original string with no leading or trailing
|
||||
// whitespace for case sensitive searches.
|
||||
this._originalSearchString = searchString.trim();
|
||||
this._searchString = fixupSearchText(this._originalSearchString.toLowerCase());
|
||||
this._searchTokens =
|
||||
this.filterTokens(getUnfilteredSearchTokens(this._searchString));
|
||||
// The protocol and the host are lowercased by nsIURI, so it's fine to
|
||||
// lowercase the typed prefix, to add it back to the results later.
|
||||
this._strippedPrefix = this._originalSearchString.slice(
|
||||
0, this._originalSearchString.length - this._searchString.length
|
||||
).toLowerCase();
|
||||
// The URIs in the database are fixed-up, so we can match on a lowercased
|
||||
// host, but the path must be matched in a case sensitive way.
|
||||
let pathIndex =
|
||||
this._originalSearchString.indexOf("/", this._strippedPrefix.length);
|
||||
this._autofillUrlSearchString = fixupSearchText(
|
||||
this._originalSearchString.slice(0, pathIndex).toLowerCase() +
|
||||
this._originalSearchString.slice(pathIndex)
|
||||
);
|
||||
|
||||
this._enableActions = searchParam.split(" ").indexOf("enable-actions") != -1;
|
||||
|
||||
this._listener = autocompleteListener;
|
||||
this._autocompleteSearch = autocompleteSearch;
|
||||
// We want to store the original string for case sensitive searches.
|
||||
this._originalSearchString = searchString;
|
||||
this._trimmedOriginalSearchString = searchString.trim();
|
||||
this._searchString = fixupSearchText(this._trimmedOriginalSearchString.toLowerCase());
|
||||
|
||||
this._matchBehavior = Prefs.matchBehavior;
|
||||
// Set the default behavior for this search.
|
||||
this._behavior = this._searchString ? Prefs.defaultBehavior
|
||||
: Prefs.emptySearchDefaultBehavior;
|
||||
this._enableActions = searchParam.split(" ").indexOf("enable-actions") != -1;
|
||||
|
||||
this._searchTokens =
|
||||
this.filterTokens(getUnfilteredSearchTokens(this._searchString));
|
||||
// The protocol and the host are lowercased by nsIURI, so it's fine to
|
||||
// lowercase the typed prefix, to add it back to the results later.
|
||||
this._strippedPrefix = this._trimmedOriginalSearchString.slice(
|
||||
0, this._trimmedOriginalSearchString.length - this._searchString.length
|
||||
).toLowerCase();
|
||||
// The URIs in the database are fixed-up, so we can match on a lowercased
|
||||
// host, but the path must be matched in a case sensitive way.
|
||||
let pathIndex =
|
||||
this._trimmedOriginalSearchString.indexOf("/", this._strippedPrefix.length);
|
||||
this._autofillUrlSearchString = fixupSearchText(
|
||||
this._trimmedOriginalSearchString.slice(0, pathIndex).toLowerCase() +
|
||||
this._trimmedOriginalSearchString.slice(pathIndex)
|
||||
);
|
||||
|
||||
this._listener = autocompleteListener;
|
||||
this._autocompleteSearch = autocompleteSearch;
|
||||
|
||||
// Create a new result to add eventual matches. Note we need a result
|
||||
// regardless having matches.
|
||||
let result = Cc["@mozilla.org/autocomplete/simple-result;1"]
|
||||
@ -597,10 +618,11 @@ Search.prototype = {
|
||||
this._switchToTabQuery,
|
||||
this._searchQuery ];
|
||||
|
||||
if (this._searchTokens.length == 1) {
|
||||
yield this._matchPriorityUrl();
|
||||
} else if (this._searchTokens.length > 1) {
|
||||
if (this._searchTokens.length > 0 &&
|
||||
PlacesUtils.bookmarks.getURIForKeyword(this._searchTokens[0])) {
|
||||
queries.unshift(this._keywordQuery);
|
||||
} else if (this._searchTokens.length == 1) {
|
||||
yield this._matchPriorityUrl();
|
||||
}
|
||||
|
||||
if (this._shouldAutofill) {
|
||||
@ -638,7 +660,7 @@ Search.prototype = {
|
||||
this._matchBehavior = MATCH_ANYWHERE;
|
||||
for (let [query, params] of [ this._adaptiveQuery,
|
||||
this._searchQuery ]) {
|
||||
yield conn.executeCached(query, params, this._onResultRow);
|
||||
yield conn.executeCached(query, params, this._onResultRow.bind(this));
|
||||
if (!this.pending)
|
||||
return;
|
||||
}
|
||||
@ -714,8 +736,9 @@ Search.prototype = {
|
||||
}
|
||||
|
||||
// Must check both id and url, cause keywords dinamically modify the url.
|
||||
let urlMapKey = stripHttpAndTrim(match.value);
|
||||
if ((!match.placeId || !this._usedPlaceIds.has(match.placeId)) &&
|
||||
!this._usedURLs.has(stripPrefix(match.value))) {
|
||||
!this._usedURLs.has(urlMapKey)) {
|
||||
// Add this to our internal tracker to ensure duplicates do not end up in
|
||||
// the result.
|
||||
// Not all entries have a place id, thus we fallback to the url for them.
|
||||
@ -724,7 +747,7 @@ Search.prototype = {
|
||||
// are faster too.
|
||||
if (match.placeId)
|
||||
this._usedPlaceIds.add(match.placeId);
|
||||
this._usedURLs.add(stripPrefix(match.value));
|
||||
this._usedURLs.add(urlMapKey);
|
||||
|
||||
this._result.appendMatch(match.value,
|
||||
match.comment,
|
||||
@ -756,8 +779,7 @@ Search.prototype = {
|
||||
// If the untrimmed value doesn't preserve the user's input just
|
||||
// ignore it and complete to the found host.
|
||||
if (untrimmedHost &&
|
||||
!untrimmedHost.toLowerCase().contains(this._originalSearchString.toLowerCase())) {
|
||||
// THIS CAUSES null TO BE SHOWN AS TITLE.
|
||||
!untrimmedHost.toLowerCase().contains(this._trimmedOriginalSearchString.toLowerCase())) {
|
||||
untrimmedHost = null;
|
||||
}
|
||||
|
||||
@ -791,8 +813,7 @@ Search.prototype = {
|
||||
// ignore it and complete to the found url.
|
||||
let untrimmedURL = prefix + url;
|
||||
if (untrimmedURL &&
|
||||
!untrimmedURL.toLowerCase().contains(this._originalSearchString.toLowerCase())) {
|
||||
// THIS CAUSES null TO BE SHOWN AS TITLE.
|
||||
!untrimmedURL.toLowerCase().contains(this._trimmedOriginalSearchString.toLowerCase())) {
|
||||
untrimmedURL = null;
|
||||
}
|
||||
|
||||
@ -870,6 +891,9 @@ Search.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
if (action)
|
||||
match.style = "action " + match.style;
|
||||
|
||||
match.value = url;
|
||||
match.comment = title;
|
||||
if (iconurl) {
|
||||
@ -927,7 +951,7 @@ Search.prototype = {
|
||||
get _keywordQuery() {
|
||||
// The keyword is the first word in the search string, with the parameters
|
||||
// following it.
|
||||
let searchString = this._originalSearchString;
|
||||
let searchString = this._trimmedOriginalSearchString;
|
||||
let queryString = "";
|
||||
let queryIndex = searchString.indexOf(" ");
|
||||
if (queryIndex != -1) {
|
||||
@ -999,6 +1023,14 @@ Search.prototype = {
|
||||
if (Prefs.defaultBehavior != DEFAULT_BEHAVIOR)
|
||||
return false;
|
||||
|
||||
// Don't try to autofill if the search term includes any whitespace.
|
||||
// This may confuse completeDefaultIndex cause the AUTOCOMPLETE_MATCH
|
||||
// tokenizer ends up trimming the search string and returning a value
|
||||
// that doesn't match it, or is even shorter.
|
||||
if (/\s/.test(this._originalSearchString)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't autoFill if the search term is recognized as a keyword, otherwise
|
||||
// it will override default keywords behavior. Note that keywords are
|
||||
// hashed on first use, so while the first query may delay a little bit,
|
||||
@ -1008,14 +1040,6 @@ Search.prototype = {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't try to autofill if the search term includes any whitespace.
|
||||
// This may confuse completeDefaultIndex cause the AUTOCOMPLETE_MATCH
|
||||
// tokenizer ends up trimming the search string and returning a value
|
||||
// that doesn't match it, or is even shorter.
|
||||
if (/\s/.test(this._searchString)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
@ -1026,7 +1050,7 @@ Search.prototype = {
|
||||
* database with and an object containing the params to bound.
|
||||
*/
|
||||
get _hostQuery() [
|
||||
Prefs.autofillTyped ? SQL_TYPED_HOST_QUERY : SQL_TYPED_QUERY,
|
||||
Prefs.autofillTyped ? SQL_TYPED_HOST_QUERY : SQL_HOST_QUERY,
|
||||
{
|
||||
query_type: QUERYTYPE_AUTOFILL_HOST,
|
||||
searchString: this._searchString.toLowerCase()
|
||||
@ -1040,7 +1064,7 @@ Search.prototype = {
|
||||
* database with and an object containing the params to bound.
|
||||
*/
|
||||
get _urlQuery() [
|
||||
Prefs.autofillTyped ? SQL_TYPED_HOST_QUERY : SQL_TYPED_QUERY,
|
||||
Prefs.autofillTyped ? SQL_TYPED_URL_QUERY : SQL_URL_QUERY,
|
||||
{
|
||||
query_type: QUERYTYPE_AUTOFILL_URL,
|
||||
searchString: this._autofillUrlSearchString,
|
||||
@ -1117,7 +1141,8 @@ UnifiedComplete.prototype = {
|
||||
yield SwitchToTabStorage.initDatabase(conn);
|
||||
|
||||
return conn;
|
||||
}.bind(this)).then(null, Cu.reportError);
|
||||
}.bind(this)).then(null, ex => { dump("Couldn't get database handle: " + ex + "\n");
|
||||
Cu.reportError(ex); });
|
||||
}
|
||||
return this._promiseDatabase;
|
||||
},
|
||||
@ -1175,7 +1200,8 @@ UnifiedComplete.prototype = {
|
||||
if (search == this._currentSearch) {
|
||||
this.finishSearch(true);
|
||||
}
|
||||
}, Cu.reportError);
|
||||
}, ex => { dump("Query failed: " + ex + "\n");
|
||||
Cu.reportError(ex); });
|
||||
},
|
||||
|
||||
stopSearch: function () {
|
||||
|
@ -15,6 +15,7 @@ XPCSHELL_TESTS_MANIFESTS += [
|
||||
'migration/xpcshell.ini',
|
||||
'network/xpcshell.ini',
|
||||
'queries/xpcshell.ini',
|
||||
'unifiedcomplete/xpcshell.ini',
|
||||
'unit/xpcshell.ini',
|
||||
'xpcshell.ini',
|
||||
]
|
||||
|
@ -0,0 +1,271 @@
|
||||
/* 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/. */
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// Import common head.
|
||||
let (commonFile = do_get_file("../head_common.js", false)) {
|
||||
let uri = Services.io.newFileURI(commonFile);
|
||||
Services.scriptloader.loadSubScript(uri.spec, this);
|
||||
}
|
||||
|
||||
// Put any other stuff relative to this test folder below.
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function* cleanup() {
|
||||
Services.prefs.clearUserPref("browser.urlbar.autocomplete.enabled");
|
||||
Services.prefs.clearUserPref("browser.urlbar.autoFill");
|
||||
Services.prefs.clearUserPref("browser.urlbar.autoFill.typed");
|
||||
remove_all_bookmarks();
|
||||
yield promiseClearHistory();
|
||||
}
|
||||
do_register_cleanup(cleanup);
|
||||
|
||||
/**
|
||||
* @param aSearches
|
||||
* Array of AutoCompleteSearch names.
|
||||
*/
|
||||
function AutoCompleteInput(aSearches) {
|
||||
this.searches = aSearches;
|
||||
}
|
||||
AutoCompleteInput.prototype = {
|
||||
popup: {
|
||||
selectedIndex: -1,
|
||||
invalidate: function () {},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompletePopup])
|
||||
},
|
||||
popupOpen: false,
|
||||
|
||||
disableAutoComplete: false,
|
||||
completeDefaultIndex: true,
|
||||
completeSelectedIndex: true,
|
||||
forceComplete: false,
|
||||
|
||||
minResultsForPopup: 0,
|
||||
maxRows: 0,
|
||||
|
||||
showCommentColumn: false,
|
||||
showImageColumn: false,
|
||||
|
||||
timeout: 10,
|
||||
searchParam: "",
|
||||
|
||||
get searchCount() {
|
||||
return this.searches.length;
|
||||
},
|
||||
getSearchAt: function(aIndex) {
|
||||
return this.searches[aIndex];
|
||||
},
|
||||
|
||||
textValue: "",
|
||||
// Text selection range
|
||||
_selStart: 0,
|
||||
_selEnd: 0,
|
||||
get selectionStart() {
|
||||
return this._selStart;
|
||||
},
|
||||
get selectionEnd() {
|
||||
return this._selEnd;
|
||||
},
|
||||
selectTextRange: function(aStart, aEnd) {
|
||||
this._selStart = aStart;
|
||||
this._selEnd = aEnd;
|
||||
},
|
||||
|
||||
onSearchBegin: function () {},
|
||||
onSearchComplete: function () {},
|
||||
|
||||
onTextEntered: function() false,
|
||||
onTextReverted: function() false,
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteInput])
|
||||
}
|
||||
|
||||
function* check_autocomplete(test) {
|
||||
// At this point frecency could still be updating due to latest pages
|
||||
// updates.
|
||||
// This is not a problem in real life, but autocomplete tests should
|
||||
// return reliable resultsets, thus we have to wait.
|
||||
yield promiseAsyncUpdates();
|
||||
|
||||
// Make an AutoCompleteInput that uses our searches and confirms results.
|
||||
let input = new AutoCompleteInput(["unifiedcomplete"]);
|
||||
input.textValue = test.search;
|
||||
|
||||
if (test.searchParam)
|
||||
input.searchParam = test.searchParam;
|
||||
|
||||
// Caret must be at the end for autoFill to happen.
|
||||
let strLen = test.search.length;
|
||||
input.selectTextRange(strLen, strLen);
|
||||
Assert.equal(input.selectionStart, strLen, "Selection starts at end");
|
||||
Assert.equal(input.selectionEnd, strLen, "Selection ends at the end");
|
||||
|
||||
let controller = Cc["@mozilla.org/autocomplete/controller;1"]
|
||||
.getService(Ci.nsIAutoCompleteController);
|
||||
controller.input = input;
|
||||
|
||||
let numSearchesStarted = 0;
|
||||
input.onSearchBegin = () => {
|
||||
do_log_info("onSearchBegin received");
|
||||
numSearchesStarted++;
|
||||
};
|
||||
let deferred = Promise.defer();
|
||||
input.onSearchComplete = () => {
|
||||
do_log_info("onSearchComplete received");
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
do_log_info("Searching for: '" + test.search + "'");
|
||||
controller.startSearch(test.search);
|
||||
yield deferred.promise;
|
||||
|
||||
// We should be running only one query.
|
||||
Assert.equal(numSearchesStarted, 1, "Only one search started");
|
||||
|
||||
// Check to see the expected uris and titles match up (in any order)
|
||||
if (test.matches) {
|
||||
for (let i = 0; i < controller.matchCount; i++) {
|
||||
let value = controller.getValueAt(i);
|
||||
let comment = controller.getCommentAt(i);
|
||||
do_log_info("Looking for '" + value + "', '" + comment + "' in expected results...");
|
||||
let j;
|
||||
for (j = 0; j < test.matches.length; j++) {
|
||||
// Skip processed expected results
|
||||
if (test.matches[j] == undefined)
|
||||
continue;
|
||||
|
||||
let { uri, title, tags } = test.matches[j];
|
||||
if (tags)
|
||||
title += " \u2013 " + tags.sort().join(", ");
|
||||
|
||||
do_log_info("Checking against expected '" + uri.spec + "', '" + title + "'...");
|
||||
// Got a match on both uri and title?
|
||||
if (stripPrefix(uri.spec) == stripPrefix(value) && title == comment) {
|
||||
do_log_info("Got a match at index " + j + "!");
|
||||
// Make it undefined so we don't process it again
|
||||
test.matches[j] = undefined;
|
||||
if (uri.spec.startsWith("moz-action:")) {
|
||||
let style = controller.getStyleAt(i);
|
||||
Assert.ok(style.contains("action"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We didn't hit the break, so we must have not found it
|
||||
if (j == test.matches.length)
|
||||
do_throw("Didn't find the current result ('" + value + "', '" + comment + "') in matches");
|
||||
}
|
||||
|
||||
Assert.equal(controller.matchCount, test.matches.length,
|
||||
"Got as many results as expected");
|
||||
|
||||
// If we expect results, make sure we got matches.
|
||||
do_check_eq(controller.searchStatus, test.matches.length ?
|
||||
Ci.nsIAutoCompleteController.STATUS_COMPLETE_MATCH :
|
||||
Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH);
|
||||
}
|
||||
|
||||
if (test.autofilled) {
|
||||
// Check the autoFilled result.
|
||||
Assert.equal(input.textValue, test.autofilled,
|
||||
"Autofilled value is correct");
|
||||
|
||||
// Now force completion and check correct casing of the result.
|
||||
// This ensures the controller is able to do its magic case-preserving
|
||||
// stuff and correct replacement of the user's casing with result's one.
|
||||
controller.handleEnter(false);
|
||||
Assert.equal(input.textValue, test.completed,
|
||||
"Completed value is correct");
|
||||
}
|
||||
}
|
||||
|
||||
function addBookmark(aBookmarkObj) {
|
||||
Assert.ok(!!aBookmarkObj.uri, "Bookmark object contains an uri");
|
||||
let parentId = aBookmarkObj.parentId ? aBookmarkObj.parentId
|
||||
: PlacesUtils.unfiledBookmarksFolderId;
|
||||
let itemId = PlacesUtils.bookmarks
|
||||
.insertBookmark(parentId,
|
||||
aBookmarkObj.uri,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
aBookmarkObj.title || "A bookmark");
|
||||
if (aBookmarkObj.keyword) {
|
||||
PlacesUtils.bookmarks.setKeywordForBookmark(itemId, aBookmarkObj.keyword);
|
||||
}
|
||||
|
||||
if (aBookmarkObj.tags) {
|
||||
PlacesUtils.tagging.tagURI(aBookmarkObj.uri, aBookmarkObj.tags);
|
||||
}
|
||||
}
|
||||
|
||||
function addOpenPages(aUri, aCount=1) {
|
||||
let ac = Cc["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"]
|
||||
.getService(Ci.mozIPlacesAutoComplete);
|
||||
for (let i = 0; i < aCount; i++) {
|
||||
ac.registerOpenPage(aUri);
|
||||
}
|
||||
}
|
||||
|
||||
function removeOpenPages(aUri, aCount=1) {
|
||||
let ac = Cc["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"]
|
||||
.getService(Ci.mozIPlacesAutoComplete);
|
||||
for (let i = 0; i < aCount; i++) {
|
||||
ac.unregisterOpenPage(aUri);
|
||||
}
|
||||
}
|
||||
|
||||
function changeRestrict(aType, aChar) {
|
||||
let branch = "browser.urlbar.";
|
||||
// "title" and "url" are different from everything else, so special case them.
|
||||
if (aType == "title" || aType == "url")
|
||||
branch += "match.";
|
||||
else
|
||||
branch += "restrict.";
|
||||
|
||||
do_log_info("changing restrict for " + aType + " to '" + aChar + "'");
|
||||
Services.prefs.setCharPref(branch + aType, aChar);
|
||||
}
|
||||
|
||||
function resetRestrict(aType) {
|
||||
let branch = "browser.urlbar.";
|
||||
// "title" and "url" are different from everything else, so special case them.
|
||||
if (aType == "title" || aType == "url")
|
||||
branch += "match.";
|
||||
else
|
||||
branch += "restrict.";
|
||||
|
||||
Services.prefs.clearUserPref(branch + aType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip prefixes from the URI that we don't care about for searching.
|
||||
*
|
||||
* @param spec
|
||||
* The text to modify.
|
||||
* @return the modified spec.
|
||||
*/
|
||||
function stripPrefix(spec)
|
||||
{
|
||||
["http://", "https://", "ftp://"].some(scheme => {
|
||||
if (spec.startsWith(scheme)) {
|
||||
spec = spec.slice(scheme.length);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (spec.startsWith("www.")) {
|
||||
spec = spec.slice(4);
|
||||
}
|
||||
return spec;
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/* 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 bug 416211 to make sure results that match the tag show the bookmark
|
||||
* title instead of the page title.
|
||||
*/
|
||||
|
||||
add_task(function* test_tag_match_has_bookmark_title() {
|
||||
do_log_info("Make sure the tag match gives the bookmark title");
|
||||
let uri = NetUtil.newURI("http://theuri/");
|
||||
yield promiseAddVisits({ uri: uri, title: "Page title" });
|
||||
addBookmark({ uri: uri,
|
||||
title: "Bookmark title",
|
||||
tags: [ "superTag" ]});
|
||||
yield check_autocomplete({
|
||||
search: "superTag",
|
||||
matches: [ { uri: uri, title: "Bookmark title", tags: [ "superTag" ] } ]
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
@ -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/. */
|
||||
|
||||
/*
|
||||
* Test autocomplete for non-English URLs that match the tag bug 416214. Also
|
||||
* test bug 417441 by making sure escaped ascii characters like "+" remain
|
||||
* escaped.
|
||||
*
|
||||
* - add a visit for a page with a non-English URL
|
||||
* - add a tag for the page
|
||||
* - search for the tag
|
||||
* - test number of matches (should be exactly one)
|
||||
* - make sure the url is decoded
|
||||
*/
|
||||
|
||||
add_task(function* test_tag_match_url() {
|
||||
do_log_info("Make sure tag matches return the right url as well as '+' remain escaped");
|
||||
let uri1 = NetUtil.newURI("http://escaped/ユニコード");
|
||||
let uri2 = NetUtil.newURI("http://asciiescaped/blocking-firefox3%2B");
|
||||
yield promiseAddVisits([ { uri: uri1, title: "title" },
|
||||
{ uri: uri2, title: "title" } ]);
|
||||
addBookmark({ uri: uri1,
|
||||
title: "title",
|
||||
tags: [ "superTag" ]});
|
||||
addBookmark({ uri: uri2,
|
||||
title: "title",
|
||||
tags: [ "superTag" ]});
|
||||
yield check_autocomplete({
|
||||
search: "superTag",
|
||||
matches: [ { uri: uri1, title: "title", tags: [ "superTag" ] },
|
||||
{ uri: uri2, title: "title", tags: [ "superTag" ] } ]
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,49 @@
|
||||
/* 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 for bug 417798 to make sure javascript: URIs don't show up unless the
|
||||
* user searches for javascript: explicitly.
|
||||
*/
|
||||
|
||||
add_task(function* test_javascript_match() {
|
||||
let uri1 = NetUtil.newURI("http://abc/def");
|
||||
let uri2 = NetUtil.newURI("javascript:5");
|
||||
yield promiseAddVisits([ { uri: uri1, title: "Title with javascript:" } ]);
|
||||
addBookmark({ uri: uri2,
|
||||
title: "Title with javascript:" });
|
||||
|
||||
do_log_info("Match non-javascript: with plain search");
|
||||
yield check_autocomplete({
|
||||
search: "a",
|
||||
matches: [ { uri: uri1, title: "Title with javascript:" } ]
|
||||
});
|
||||
|
||||
do_log_info("Match non-javascript: with almost javascript:");
|
||||
yield check_autocomplete({
|
||||
search: "javascript",
|
||||
matches: [ { uri: uri1, title: "Title with javascript:" } ]
|
||||
});
|
||||
|
||||
do_log_info("Match javascript:");
|
||||
yield check_autocomplete({
|
||||
search: "javascript:",
|
||||
matches: [ { uri: uri1, title: "Title with javascript:" },
|
||||
{ uri: uri2, title: "Title with javascript:" } ]
|
||||
});
|
||||
|
||||
do_log_info("Match nothing with non-first javascript:");
|
||||
yield check_autocomplete({
|
||||
search: "5 javascript:",
|
||||
matches: [ ]
|
||||
});
|
||||
|
||||
do_log_info("Match javascript: with multi-word search");
|
||||
yield check_autocomplete({
|
||||
search: "javascript: 5",
|
||||
matches: [ { uri: uri2, title: "Title with javascript:" } ]
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,65 @@
|
||||
/* 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 bug 418257 by making sure tags are returned with the title as part of
|
||||
* the "comment" if there are tags even if we didn't match in the tags. They
|
||||
* are separated from the title by a endash.
|
||||
*/
|
||||
|
||||
add_task(function* test_javascript_match() {
|
||||
let uri1 = NetUtil.newURI("http://page1");
|
||||
let uri2 = NetUtil.newURI("http://page2");
|
||||
let uri3 = NetUtil.newURI("http://page3");
|
||||
let uri4 = NetUtil.newURI("http://page4");
|
||||
yield promiseAddVisits([ { uri: uri1, title: "tagged" },
|
||||
{ uri: uri2, title: "tagged" },
|
||||
{ uri: uri3, title: "tagged" },
|
||||
{ uri: uri4, title: "tagged" } ]);
|
||||
addBookmark({ uri: uri1,
|
||||
title: "tagged",
|
||||
tags: [ "tag1" ] });
|
||||
addBookmark({ uri: uri2,
|
||||
title: "tagged",
|
||||
tags: [ "tag1", "tag2" ] });
|
||||
addBookmark({ uri: uri3,
|
||||
title: "tagged",
|
||||
tags: [ "tag1", "tag3" ] });
|
||||
addBookmark({ uri: uri4,
|
||||
title: "tagged",
|
||||
tags: [ "tag1", "tag2", "tag3" ] });
|
||||
|
||||
do_log_info("Make sure tags come back in the title when matching tags");
|
||||
yield check_autocomplete({
|
||||
search: "page1 tag",
|
||||
matches: [ { uri: uri1, title: "tagged", tags: [ "tag1" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("Check tags in title for page2");
|
||||
yield check_autocomplete({
|
||||
search: "page2 tag",
|
||||
matches: [ { uri: uri2, title: "tagged", tags: [ "tag1", "tag2" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("Make sure tags appear even when not matching the tag");
|
||||
yield check_autocomplete({
|
||||
search: "page3",
|
||||
matches: [ { uri: uri3, title: "tagged", tags: [ "tag1", "tag3" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("Multiple tags come in commas for page4");
|
||||
yield check_autocomplete({
|
||||
search: "page4",
|
||||
matches: [ { uri: uri4, title: "tagged", tags: [ "tag1", "tag2", "tag3" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("Extra test just to make sure we match the title");
|
||||
yield check_autocomplete({
|
||||
search: "tag2",
|
||||
matches: [ { uri: uri2, title: "tagged", tags: [ "tag1", "tag2" ] },
|
||||
{ uri: uri4, title: "tagged", tags: [ "tag1", "tag2", "tag3" ] } ]
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,19 @@
|
||||
/* 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 bug 422277 to make sure bad escaped uris don't get escaped. This makes
|
||||
* sure we don't hit an assertion for "not a UTF8 string".
|
||||
*/
|
||||
|
||||
add_task(function* test_javascript_match() {
|
||||
do_log_info("Bad escaped uri stays escaped");
|
||||
let uri1 = NetUtil.newURI("http://site/%EAid");
|
||||
yield promiseAddVisits([ { uri: uri1, title: "title" } ]);
|
||||
yield check_autocomplete({
|
||||
search: "site",
|
||||
matches: [ { uri: uri1, title: "title" } ]
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,147 @@
|
||||
/* 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/. */
|
||||
|
||||
// Functional tests for inline autocomplete
|
||||
|
||||
add_task(function* test_disabling_autocomplete() {
|
||||
do_log_info("Check disabling autocomplete disables autofill");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autocomplete.enabled", false);
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://visit.mozilla.org"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "vis",
|
||||
autofilled: "vis",
|
||||
completed: "vis"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_urls_order() {
|
||||
do_log_info("Add urls, check for correct order");
|
||||
let places = [{ uri: NetUtil.newURI("http://visit1.mozilla.org") },
|
||||
{ uri: NetUtil.newURI("http://visit2.mozilla.org"),
|
||||
transition: TRANSITION_TYPED }];
|
||||
yield promiseAddVisits(places);
|
||||
yield check_autocomplete({
|
||||
search: "vis",
|
||||
autofilled: "visit2.mozilla.org/",
|
||||
completed: "visit2.mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_ignore_prefix() {
|
||||
do_log_info("Add urls, make sure www and http are ignored");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
yield promiseAddVisits(NetUtil.newURI("http://www.visit1.mozilla.org"));
|
||||
yield check_autocomplete({
|
||||
search: "visit1",
|
||||
autofilled: "visit1.mozilla.org/",
|
||||
completed: "visit1.mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_after_host() {
|
||||
do_log_info("Autocompleting after an existing host completes to the url");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
yield promiseAddVisits(NetUtil.newURI("http://www.visit3.mozilla.org"));
|
||||
yield check_autocomplete({
|
||||
search: "visit3.mozilla.org/",
|
||||
autofilled: "visit3.mozilla.org/",
|
||||
completed: "visit3.mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_respect_www() {
|
||||
do_log_info("Searching for www.me should yield www.me.mozilla.org/");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
yield promiseAddVisits(NetUtil.newURI("http://www.me.mozilla.org"));
|
||||
yield check_autocomplete({
|
||||
search: "www.me",
|
||||
autofilled: "www.me.mozilla.org/",
|
||||
completed: "www.me.mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_bookmark_first() {
|
||||
do_log_info("With a bookmark and history, the query result should be the bookmark");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
addBookmark({ uri: NetUtil.newURI("http://bookmark1.mozilla.org/") });
|
||||
yield promiseAddVisits(NetUtil.newURI("http://bookmark1.mozilla.org/foo"));
|
||||
yield check_autocomplete({
|
||||
search: "bookmark",
|
||||
autofilled: "bookmark1.mozilla.org/",
|
||||
completed: "bookmark1.mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_full_path() {
|
||||
do_log_info("Check to make sure we get the proper results with full paths");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
let places = [{ uri: NetUtil.newURI("http://smokey.mozilla.org/foo/bar/baz?bacon=delicious") },
|
||||
{ uri: NetUtil.newURI("http://smokey.mozilla.org/foo/bar/baz?bacon=smokey") }];
|
||||
yield promiseAddVisits(places);
|
||||
yield check_autocomplete({
|
||||
search: "smokey",
|
||||
autofilled: "smokey.mozilla.org/",
|
||||
completed: "smokey.mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_complete_to_slash() {
|
||||
do_log_info("Check to make sure we autocomplete to the following '/'");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
let places = [{ uri: NetUtil.newURI("http://smokey.mozilla.org/foo/bar/baz?bacon=delicious") },
|
||||
{ uri: NetUtil.newURI("http://smokey.mozilla.org/foo/bar/baz?bacon=smokey") }];
|
||||
yield promiseAddVisits(places);
|
||||
yield check_autocomplete({
|
||||
search: "smokey.mozilla.org/fo",
|
||||
autofilled: "smokey.mozilla.org/foo/",
|
||||
completed: "http://smokey.mozilla.org/foo/",
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_complete_to_slash_with_www() {
|
||||
do_log_info("Check to make sure we autocomplete to the following '/'");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
let places = [{ uri: NetUtil.newURI("http://www.smokey.mozilla.org/foo/bar/baz?bacon=delicious") },
|
||||
{ uri: NetUtil.newURI("http://www.smokey.mozilla.org/foo/bar/baz?bacon=smokey") }];
|
||||
yield promiseAddVisits(places);
|
||||
yield check_autocomplete({
|
||||
search: "smokey.mozilla.org/fo",
|
||||
autofilled: "smokey.mozilla.org/foo/",
|
||||
completed: "http://www.smokey.mozilla.org/foo/",
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_complete_querystring() {
|
||||
do_log_info("Check to make sure we autocomplete after ?");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
yield promiseAddVisits(NetUtil.newURI("http://smokey.mozilla.org/foo?bacon=delicious"));
|
||||
yield check_autocomplete({
|
||||
search: "smokey.mozilla.org/foo?",
|
||||
autofilled: "smokey.mozilla.org/foo?bacon=delicious",
|
||||
completed: "http://smokey.mozilla.org/foo?bacon=delicious",
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_complete_fragment() {
|
||||
do_log_info("Check to make sure we autocomplete after #");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
yield promiseAddVisits(NetUtil.newURI("http://smokey.mozilla.org/foo?bacon=delicious#bar"));
|
||||
yield check_autocomplete({
|
||||
search: "smokey.mozilla.org/foo?bacon=delicious#bar",
|
||||
autofilled: "smokey.mozilla.org/foo?bacon=delicious#bar",
|
||||
completed: "http://smokey.mozilla.org/foo?bacon=delicious#bar",
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,39 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */
|
||||
|
||||
/*
|
||||
* Need to test that removing a page from autocomplete actually removes a page
|
||||
* Description From Shawn Wilsher :sdwilsh 2009-02-18 11:29:06 PST
|
||||
* We don't test the code path of onValueRemoved
|
||||
* for the autocomplete implementation
|
||||
* Bug 479089
|
||||
*/
|
||||
|
||||
add_task(function* test_autocomplete_on_value_removed() {
|
||||
let listener = Cc["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"].
|
||||
getService(Components.interfaces.nsIAutoCompleteSimpleResultListener);
|
||||
|
||||
let testUri = NetUtil.newURI("http://foo.mozilla.com/");
|
||||
yield promiseAddVisits({
|
||||
uri: testUri,
|
||||
referrer: uri("http://mozilla.com/")
|
||||
});
|
||||
|
||||
let query = PlacesUtils.history.getNewQuery();
|
||||
let options = PlacesUtils.history.getNewQueryOptions();
|
||||
// look for this uri only
|
||||
query.uri = testUri;
|
||||
|
||||
let root = PlacesUtils.history.executeQuery(query, options).root;
|
||||
root.containerOpen = true;
|
||||
Assert.equal(root.childCount, 1);
|
||||
// call the untested code path
|
||||
listener.onValueRemoved(null, testUri.spec, true);
|
||||
// make sure it is GONE from the DB
|
||||
Assert.equal(root.childCount, 0);
|
||||
// close the container
|
||||
root.containerOpen = false;
|
||||
});
|
135
toolkit/components/places/tests/unifiedcomplete/test_casing.js
Normal file
135
toolkit/components/places/tests/unifiedcomplete/test_casing.js
Normal file
@ -0,0 +1,135 @@
|
||||
/* 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_casing_1() {
|
||||
do_log_info("Searching for cased entry 1");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "MOZ",
|
||||
autofilled: "MOZilla.org/",
|
||||
completed: "mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_casing_2() {
|
||||
do_log_info("Searching for cased entry 2");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mozilla.org/T",
|
||||
autofilled: "mozilla.org/T",
|
||||
completed: "mozilla.org/T"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_casing_3() {
|
||||
do_log_info("Searching for cased entry 3");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mozilla.org/T",
|
||||
autofilled: "mozilla.org/Test/",
|
||||
completed: "http://mozilla.org/Test/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_casing_4() {
|
||||
do_log_info("Searching for cased entry 4");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mOzilla.org/t",
|
||||
autofilled: "mOzilla.org/t",
|
||||
completed: "mOzilla.org/t"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_casing_5() {
|
||||
do_log_info("Searching for cased entry 5");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mOzilla.org/T",
|
||||
autofilled: "mOzilla.org/Test/",
|
||||
completed: "http://mozilla.org/Test/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untrimmed_casing() {
|
||||
do_log_info("Searching for untrimmed cased entry");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "http://mOz",
|
||||
autofilled: "http://mOzilla.org/",
|
||||
completed: "http://mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untrimmed_www_casing() {
|
||||
do_log_info("Searching for untrimmed cased entry with www");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://www.mozilla.org/Test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "http://www.mOz",
|
||||
autofilled: "http://www.mOzilla.org/",
|
||||
completed: "http://www.mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untrimmed_path_casing() {
|
||||
do_log_info("Searching for untrimmed cased entry with path");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "http://mOzilla.org/t",
|
||||
autofilled: "http://mOzilla.org/t",
|
||||
completed: "http://mOzilla.org/t"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untrimmed_path_casing_2() {
|
||||
do_log_info("Searching for untrimmed cased entry with path 2");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/Test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "http://mOzilla.org/T",
|
||||
autofilled: "http://mOzilla.org/Test/",
|
||||
completed: "http://mozilla.org/Test/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untrimmed_path_www_casing() {
|
||||
do_log_info("Searching for untrimmed cased entry with www and path");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://www.mozilla.org/Test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "http://www.mOzilla.org/t",
|
||||
autofilled: "http://www.mOzilla.org/t",
|
||||
completed: "http://www.mOzilla.org/t"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untrimmed_path_www_casing_2() {
|
||||
do_log_info("Searching for untrimmed cased entry with www and path 2");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://www.mozilla.org/Test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "http://www.mOzilla.org/T",
|
||||
autofilled: "http://www.mOzilla.org/Test/",
|
||||
completed: "http://www.mozilla.org/Test/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,79 @@
|
||||
/* 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/. */
|
||||
|
||||
// Inline should never return matches shorter than the search string, since
|
||||
// that largely confuses completeDefaultIndex
|
||||
|
||||
add_task(function* test_not_autofill_ws_1() {
|
||||
do_log_info("Do not autofill whitespaced entry 1");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/link/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mozilla.org ",
|
||||
autofilled: "mozilla.org ",
|
||||
completed: "mozilla.org "
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_not_autofill_ws_2() {
|
||||
do_log_info("Do not autofill whitespaced entry 2");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/link/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mozilla.org/ ",
|
||||
autofilled: "mozilla.org/ ",
|
||||
completed: "mozilla.org/ "
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_not_autofill_ws_3() {
|
||||
do_log_info("Do not autofill whitespaced entry 3");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/link/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mozilla.org/link ",
|
||||
autofilled: "mozilla.org/link ",
|
||||
completed: "mozilla.org/link "
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_not_autofill_ws_4() {
|
||||
do_log_info("Do not autofill whitespaced entry 4");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/link/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mozilla.org/link/ ",
|
||||
autofilled: "mozilla.org/link/ ",
|
||||
completed: "mozilla.org/link/ "
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_not_autofill_ws_5() {
|
||||
do_log_info("Do not autofill whitespaced entry 5");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/link/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "moz illa ",
|
||||
autofilled: "moz illa ",
|
||||
completed: "moz illa "
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_not_autofill_ws_6() {
|
||||
do_log_info("Do not autofill whitespaced entry 6");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/link/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: " mozilla",
|
||||
autofilled: " mozilla",
|
||||
completed: " mozilla"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,75 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */
|
||||
|
||||
/**
|
||||
* Tests bug 449406 to ensure that TRANSITION_DOWNLOAD, TRANSITION_EMBED and
|
||||
* TRANSITION_FRAMED_LINK bookmarked uri's show up in the location bar.
|
||||
*/
|
||||
|
||||
add_task(function* test_download_embed_bookmarks() {
|
||||
let uri1 = NetUtil.newURI("http://download/bookmarked");
|
||||
let uri2 = NetUtil.newURI("http://embed/bookmarked");
|
||||
let uri3 = NetUtil.newURI("http://framed/bookmarked");
|
||||
let uri4 = NetUtil.newURI("http://download");
|
||||
let uri5 = NetUtil.newURI("http://embed");
|
||||
let uri6 = NetUtil.newURI("http://framed");
|
||||
yield promiseAddVisits([ { uri: uri1, title: "download-bookmark",
|
||||
transition: TRANSITION_DOWNLOAD },
|
||||
{ uri: uri2, title: "embed-bookmark",
|
||||
transition: TRANSITION_EMBED },
|
||||
{ uri: uri3, title: "framed-bookmark",
|
||||
transition: TRANSITION_FRAMED_LINK},
|
||||
{ uri: uri4, title: "download2",
|
||||
transition: TRANSITION_DOWNLOAD },
|
||||
{ uri: uri5, title: "embed2",
|
||||
transition: TRANSITION_EMBED },
|
||||
{ uri: uri6, title: "framed2",
|
||||
transition: TRANSITION_FRAMED_LINK } ]);
|
||||
addBookmark({ uri: uri1,
|
||||
title: "download-bookmark" });
|
||||
addBookmark({ uri: uri2,
|
||||
title: "embed-bookmark" });
|
||||
addBookmark({ uri: uri3,
|
||||
title: "framed-bookmark" });
|
||||
|
||||
do_log_info("Searching for bookmarked download uri matches");
|
||||
yield check_autocomplete({
|
||||
search: "download-bookmark",
|
||||
matches: [ { uri: uri1, title: "download-bookmark" } ]
|
||||
});
|
||||
|
||||
do_log_info("Searching for bookmarked embed uri matches");
|
||||
yield check_autocomplete({
|
||||
search: "embed-bookmark",
|
||||
matches: [ { uri: uri2, title: "embed-bookmark" } ]
|
||||
});
|
||||
|
||||
do_log_info("Searching for bookmarked framed uri matches");
|
||||
yield check_autocomplete({
|
||||
search: "framed-bookmark",
|
||||
matches: [ { uri: uri3, title: "framed-bookmark" } ]
|
||||
});
|
||||
|
||||
do_log_info("Searching for download uri does not match");
|
||||
yield check_autocomplete({
|
||||
search: "download2",
|
||||
matches: [ ]
|
||||
});
|
||||
|
||||
do_log_info("Searching for embed uri does not match");
|
||||
yield check_autocomplete({
|
||||
search: "embed2",
|
||||
matches: [ ]
|
||||
});
|
||||
|
||||
do_log_info("Searching for framed uri does not match");
|
||||
yield check_autocomplete({
|
||||
search: "framed2",
|
||||
matches: [ ]
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,18 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Ensure inline autocomplete doesn't return zero frecency pages.
|
||||
|
||||
add_task(function* test_dupe_urls() {
|
||||
do_log_info("Searching for urls with dupes should only show one");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("http://mozilla.org/?") });
|
||||
yield check_autocomplete({
|
||||
search: "moz",
|
||||
autofilled: "mozilla.org/",
|
||||
completed: "mozilla.org/",
|
||||
matches: [ { uri: NetUtil.newURI("http://mozilla.org/"), title: "mozilla.org/" } ]
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,94 @@
|
||||
/* 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 for bug 426864 that makes sure the empty search (drop down list) only
|
||||
* shows typed pages from history.
|
||||
*/
|
||||
|
||||
add_task(function* test_javascript_match() {
|
||||
let uri1 = NetUtil.newURI("http://t.foo/0");
|
||||
let uri2 = NetUtil.newURI("http://t.foo/1");
|
||||
let uri3 = NetUtil.newURI("http://t.foo/2");
|
||||
let uri4 = NetUtil.newURI("http://t.foo/3");
|
||||
let uri5 = NetUtil.newURI("http://t.foo/4");
|
||||
let uri6 = NetUtil.newURI("http://t.foo/5");
|
||||
|
||||
yield promiseAddVisits([ { uri: uri1, title: "title" },
|
||||
{ uri: uri2, title: "title" },
|
||||
{ uri: uri3, title: "title",
|
||||
transition: TRANSITION_TYPED},
|
||||
{ uri: uri4, title: "title",
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: uri6, title: "title",
|
||||
transition: TRANSITION_TYPED } ]);
|
||||
|
||||
addBookmark({ uri: uri2,
|
||||
title: "title" });
|
||||
addBookmark({ uri: uri4,
|
||||
title: "title" });
|
||||
addBookmark({ uri: uri5,
|
||||
title: "title" });
|
||||
addBookmark({ uri: uri6,
|
||||
title: "title" });
|
||||
|
||||
// Now remove page 6 from history, so it is an unvisited, typed bookmark.
|
||||
PlacesUtils.history.removePage(uri6);
|
||||
|
||||
do_log_info("Match everything");
|
||||
yield check_autocomplete({
|
||||
search: "foo",
|
||||
matches: [ { uri: uri1, title: "title" },
|
||||
{ uri: uri2, title: "title" },
|
||||
{ uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "title" },
|
||||
{ uri: uri5, title: "title" },
|
||||
{ uri: uri6, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("Match only typed history");
|
||||
yield check_autocomplete({
|
||||
search: "foo ^ ~",
|
||||
matches: [ { uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("Drop-down empty search matches only typed history");
|
||||
yield check_autocomplete({
|
||||
search: "",
|
||||
matches: [ { uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("Drop-down empty search matches everything");
|
||||
Services.prefs.setIntPref("browser.urlbar.default.behavior.emptyRestriction", 0);
|
||||
yield check_autocomplete({
|
||||
search: "",
|
||||
matches: [ { uri: uri1, title: "title" },
|
||||
{ uri: uri2, title: "title" },
|
||||
{ uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "title" },
|
||||
{ uri: uri5, title: "title" },
|
||||
{ uri: uri6, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("Drop-down empty search matches only typed");
|
||||
Services.prefs.setIntPref("browser.urlbar.default.behavior.emptyRestriction", 32);
|
||||
yield check_autocomplete({
|
||||
search: "",
|
||||
matches: [ { uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "title" },
|
||||
{ uri: uri6, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("Drop-down empty search matches only typed history");
|
||||
Services.prefs.clearUserPref("browser.urlbar.default.behavior.emptyRestriction");
|
||||
yield check_autocomplete({
|
||||
search: "",
|
||||
matches: [ { uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "title" } ]
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
@ -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/. */
|
||||
|
||||
/**
|
||||
* Test for bug 471903 to make sure searching in autocomplete can be turned on
|
||||
* and off. Also test bug 463535 for pref changing search.
|
||||
*/
|
||||
|
||||
add_task(function* test_enabled() {
|
||||
let uri = NetUtil.newURI("http://url/0");
|
||||
yield promiseAddVisits([ { uri: uri, title: "title" } ]);
|
||||
|
||||
do_log_info("plain search");
|
||||
yield check_autocomplete({
|
||||
search: "url",
|
||||
matches: [ { uri: uri, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("search disabled");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autocomplete.enabled", false);
|
||||
yield check_autocomplete({
|
||||
search: "url",
|
||||
matches: [ ]
|
||||
});
|
||||
|
||||
do_log_info("resume normal search");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autocomplete.enabled", true);
|
||||
yield check_autocomplete({
|
||||
search: "url",
|
||||
matches: [ { uri: uri, title: "title" } ]
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,29 @@
|
||||
/* 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 bug 422698 to make sure searches with urls from the location bar
|
||||
* correctly match itself when it contains escaped characters.
|
||||
*/
|
||||
|
||||
add_task(function* test_escape() {
|
||||
let uri1 = NetUtil.newURI("http://unescapeduri/");
|
||||
let uri2 = NetUtil.newURI("http://escapeduri/%40/");
|
||||
yield promiseAddVisits([ { uri: uri1, title: "title" },
|
||||
{ uri: uri2, title: "title" } ]);
|
||||
|
||||
do_log_info("Unescaped location matches itself");
|
||||
yield check_autocomplete({
|
||||
search: "http://unescapeduri/",
|
||||
matches: [ { uri: uri1, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("Escaped location matches itself");
|
||||
yield check_autocomplete({
|
||||
search: "http://escapeduri/%40/",
|
||||
matches: [ { uri: uri2, title: "title" } ]
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,22 @@
|
||||
/* 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 bug 424509 to make sure searching for "h" doesn't match "http" of urls.
|
||||
*/
|
||||
|
||||
add_task(function* test_escape() {
|
||||
let uri1 = NetUtil.newURI("http://site/");
|
||||
let uri2 = NetUtil.newURI("http://happytimes/");
|
||||
yield promiseAddVisits([ { uri: uri1, title: "title" },
|
||||
{ uri: uri2, title: "title" } ]);
|
||||
|
||||
do_log_info("Searching for h matches site and not http://");
|
||||
yield check_autocomplete({
|
||||
search: "h",
|
||||
matches: [ { uri: uri2, title: "title" } ]
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,77 @@
|
||||
/* 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 for bug 392143 that puts keyword results into the autocomplete. Makes
|
||||
* sure that multiple parameter queries get spaces converted to +, + converted
|
||||
* to %2B, non-ascii become escaped, and pages in history that match the
|
||||
* keyword uses the page's title.
|
||||
*
|
||||
* Also test for bug 249468 by making sure multiple keyword bookmarks with the
|
||||
* same keyword appear in the list.
|
||||
*/
|
||||
|
||||
add_task(function* test_keyword_searc() {
|
||||
let uri1 = NetUtil.newURI("http://abc/?search=%s");
|
||||
let uri2 = NetUtil.newURI("http://abc/?search=ThisPageIsInHistory");
|
||||
yield promiseAddVisits([ { uri: uri1, title: "Generic page title" },
|
||||
{ uri: uri2, title: "Generic page title" } ]);
|
||||
addBookmark({ uri: uri1, title: "Keyword title", keyword: "key"});
|
||||
|
||||
do_log_info("Plain keyword query");
|
||||
yield check_autocomplete({
|
||||
search: "key term",
|
||||
matches: [ { uri: NetUtil.newURI("http://abc/?search=term"), title: "Keyword title" } ]
|
||||
});
|
||||
|
||||
do_log_info("Multi-word keyword query");
|
||||
yield check_autocomplete({
|
||||
search: "key multi word",
|
||||
matches: [ { uri: NetUtil.newURI("http://abc/?search=multi+word"), title: "Keyword title" } ]
|
||||
});
|
||||
|
||||
do_log_info("Keyword query with +");
|
||||
yield check_autocomplete({
|
||||
search: "key blocking+",
|
||||
matches: [ { uri: NetUtil.newURI("http://abc/?search=blocking%2B"), title: "Keyword title" } ]
|
||||
});
|
||||
|
||||
do_log_info("Unescaped term in query");
|
||||
yield check_autocomplete({
|
||||
search: "key ユニコード",
|
||||
matches: [ { uri: NetUtil.newURI("http://abc/?search=ユニコード"), title: "Keyword title" } ]
|
||||
});
|
||||
|
||||
do_log_info("Keyword that happens to match a page");
|
||||
yield check_autocomplete({
|
||||
search: "key ThisPageIsInHistory",
|
||||
matches: [ { uri: NetUtil.newURI("http://abc/?search=ThisPageIsInHistory"), title: "Generic page title" } ]
|
||||
});
|
||||
|
||||
do_log_info("Keyword without query (without space)");
|
||||
yield check_autocomplete({
|
||||
search: "key",
|
||||
matches: [ { uri: NetUtil.newURI("http://abc/?search="), title: "Keyword title" } ]
|
||||
});
|
||||
|
||||
do_log_info("Keyword without query (with space)");
|
||||
yield check_autocomplete({
|
||||
search: "key ",
|
||||
matches: [ { uri: NetUtil.newURI("http://abc/?search="), title: "Keyword title" } ]
|
||||
});
|
||||
|
||||
// This adds a second keyword so anything after this will match 2 keywords
|
||||
let uri3 = NetUtil.newURI("http://xyz/?foo=%s");
|
||||
yield promiseAddVisits([ { uri: uri3, title: "Generic page title" } ]);
|
||||
addBookmark({ uri: uri3, title: "Keyword title", keyword: "key"});
|
||||
|
||||
do_log_info("Two keywords matched");
|
||||
yield check_autocomplete({
|
||||
search: "key twoKey",
|
||||
matches: [ { uri: NetUtil.newURI("http://abc/?search=twoKey"), title: "Keyword title" },
|
||||
{ uri: NetUtil.newURI("http://xyz/?foo=twoKey"), title: "Keyword title" } ]
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,68 @@
|
||||
/* 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_non_keyword() {
|
||||
do_log_info("Searching for non-keyworded entry should autoFill it");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
addBookmark({ uri: NetUtil.newURI("http://mozilla.org/test/") });
|
||||
yield check_autocomplete({
|
||||
search: "moz",
|
||||
autofilled: "mozilla.org/",
|
||||
completed: "mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_keyword() {
|
||||
do_log_info("Searching for keyworded entry should not autoFill it");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
addBookmark({ uri: NetUtil.newURI("http://mozilla.org/test/"), keyword: "moz" });
|
||||
yield check_autocomplete({
|
||||
search: "moz",
|
||||
autofilled: "moz",
|
||||
completed: "moz",
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_more_than_keyword() {
|
||||
do_log_info("Searching for more than keyworded entry should autoFill it");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
addBookmark({ uri: NetUtil.newURI("http://mozilla.org/test/"), keyword: "moz" });
|
||||
yield check_autocomplete({
|
||||
search: "mozi",
|
||||
autofilled: "mozilla.org/",
|
||||
completed: "mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_less_than_keyword() {
|
||||
do_log_info("Searching for less than keyworded entry should autoFill it");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
addBookmark({ uri: NetUtil.newURI("http://mozilla.org/test/"), keyword: "moz" });
|
||||
yield check_autocomplete({
|
||||
search: "mo",
|
||||
autofilled: "mozilla.org/",
|
||||
completed: "mozilla.org/",
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_keyword_casing() {
|
||||
do_log_info("Searching for keyworded entry is case-insensitive");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
addBookmark({ uri: NetUtil.newURI("http://mozilla.org/test/"), keyword: "moz" });
|
||||
yield check_autocomplete({
|
||||
search: "MoZ",
|
||||
autofilled: "MoZ",
|
||||
completed: "MoZ"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,50 @@
|
||||
/* 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 bug 451760 which allows matching only at the beginning of urls or
|
||||
* titles to simulate Firefox 2 functionality.
|
||||
*/
|
||||
|
||||
add_task(function* test_match_beginning() {
|
||||
let uri1 = NetUtil.newURI("http://x.com/y");
|
||||
let uri2 = NetUtil.newURI("https://y.com/x");
|
||||
yield promiseAddVisits([ { uri: uri1, title: "a b" },
|
||||
{ uri: uri2, title: "b a" } ]);
|
||||
|
||||
do_log_info("Match at the beginning of titles");
|
||||
Services.prefs.setIntPref("browser.urlbar.matchBehavior", 3);
|
||||
yield check_autocomplete({
|
||||
search: "a",
|
||||
matches: [ { uri: uri1, title: "a b" } ]
|
||||
});
|
||||
|
||||
do_log_info("Match at the beginning of titles");
|
||||
yield check_autocomplete({
|
||||
search: "b",
|
||||
matches: [ { uri: uri2, title: "b a" } ]
|
||||
});
|
||||
|
||||
do_log_info("Match at the beginning of urls");
|
||||
yield check_autocomplete({
|
||||
search: "x",
|
||||
matches: [ { uri: uri1, title: "a b" } ]
|
||||
});
|
||||
|
||||
do_log_info("Match at the beginning of urls");
|
||||
yield check_autocomplete({
|
||||
search: "y",
|
||||
matches: [ { uri: uri2, title: "b a" } ]
|
||||
});
|
||||
|
||||
do_log_info("Sanity check that matching anywhere finds more");
|
||||
Services.prefs.setIntPref("browser.urlbar.matchBehavior", 1);
|
||||
yield check_autocomplete({
|
||||
search: "a",
|
||||
matches: [ { uri: uri1, title: "a b" },
|
||||
{ uri: uri2, title: "b a" } ]
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,66 @@
|
||||
/* 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 for bug 401869 to allow multiple words separated by spaces to match in
|
||||
* the page title, page url, or bookmark title to be considered a match. All
|
||||
* terms must match but not all terms need to be in the title, etc.
|
||||
*
|
||||
* Test bug 424216 by making sure bookmark titles are always shown if one is
|
||||
* available. Also bug 425056 makes sure matches aren't found partially in the
|
||||
* page title and partially in the bookmark.
|
||||
*/
|
||||
|
||||
add_task(function* test_match_beginning() {
|
||||
let uri1 = NetUtil.newURI("http://a.b.c/d-e_f/h/t/p");
|
||||
let uri2 = NetUtil.newURI("http://d.e.f/g-h_i/h/t/p");
|
||||
let uri3 = NetUtil.newURI("http://g.h.i/j-k_l/h/t/p");
|
||||
let uri4 = NetUtil.newURI("http://j.k.l/m-n_o/h/t/p");
|
||||
yield promiseAddVisits([ { uri: uri1, title: "f(o)o b<a>r" },
|
||||
{ uri: uri2, title: "b(a)r b<a>z" },
|
||||
{ uri: uri3, title: "f(o)o b<a>r" },
|
||||
{ uri: uri4, title: "f(o)o b<a>r" } ]);
|
||||
addBookmark({ uri: uri3, title: "f(o)o b<a>r" });
|
||||
addBookmark({ uri: uri4, title: "b(a)r b<a>z" });
|
||||
|
||||
do_log_info("Match 2 terms all in url");
|
||||
yield check_autocomplete({
|
||||
search: "c d",
|
||||
matches: [ { uri: uri1, title: "f(o)o b<a>r" } ]
|
||||
});
|
||||
|
||||
do_log_info("Match 1 term in url and 1 term in title");
|
||||
yield check_autocomplete({
|
||||
search: "b e",
|
||||
matches: [ { uri: uri1, title: "f(o)o b<a>r" },
|
||||
{ uri: uri2, title: "b(a)r b<a>z" } ]
|
||||
});
|
||||
|
||||
do_log_info("Match 3 terms all in title; display bookmark title if matched");
|
||||
yield check_autocomplete({
|
||||
search: "b a z",
|
||||
matches: [ { uri: uri2, title: "b(a)r b<a>z" },
|
||||
{ uri: uri4, title: "b(a)r b<a>z" } ]
|
||||
});
|
||||
|
||||
do_log_info("Match 2 terms in url and 1 in title; make sure bookmark title is used for search");
|
||||
yield check_autocomplete({
|
||||
search: "k f t",
|
||||
matches: [ { uri: uri3, title: "f(o)o b<a>r" } ]
|
||||
});
|
||||
|
||||
do_log_info("Match 3 terms in url and 1 in title");
|
||||
yield check_autocomplete({
|
||||
search: "d i g z",
|
||||
matches: [ { uri: uri2, title: "b(a)r b<a>z" } ]
|
||||
});
|
||||
|
||||
do_log_info("Match nothing");
|
||||
yield check_autocomplete({
|
||||
search: "m o z i",
|
||||
matches: [ ]
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,57 @@
|
||||
/* 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_no_slash() {
|
||||
do_log_info("Searching for host match without slash should match host");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://file.org/test/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("file:///c:/test.html"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "file",
|
||||
autofilled: "file.org/",
|
||||
completed: "file.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_w_slash() {
|
||||
do_log_info("Searching match with slash at the end should do nothing");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://file.org/test/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("file:///c:/test.html"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "file.org/",
|
||||
autofilled: "file.org/",
|
||||
completed: "file.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_middle() {
|
||||
do_log_info("Searching match with slash in the middle should match url");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://file.org/test/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("file:///c:/test.html"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "file.org/t",
|
||||
autofilled: "file.org/test/",
|
||||
completed: "http://file.org/test/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_nonhost() {
|
||||
do_log_info("Searching for non-host match without slash should not match url");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("file:///c:/test.html"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "file",
|
||||
autofilled: "file",
|
||||
completed: "file"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,419 @@
|
||||
/* 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 for bug 395161 that allows special searches that restrict results to
|
||||
* history/bookmark/tagged items and title/url matches.
|
||||
*
|
||||
* Test 485122 by making sure results don't have tags when restricting result
|
||||
* to just history either by default behavior or dynamic query restrict.
|
||||
*/
|
||||
|
||||
add_task(function* test_special_searches() {
|
||||
let uri1 = NetUtil.newURI("http://url/");
|
||||
let uri2 = NetUtil.newURI("http://url/2");
|
||||
let uri3 = NetUtil.newURI("http://foo.bar/");
|
||||
let uri4 = NetUtil.newURI("http://foo.bar/2");
|
||||
let uri5 = NetUtil.newURI("http://url/star");
|
||||
let uri6 = NetUtil.newURI("http://url/star/2");
|
||||
let uri7 = NetUtil.newURI("http://foo.bar/star");
|
||||
let uri8 = NetUtil.newURI("http://foo.bar/star/2");
|
||||
let uri9 = NetUtil.newURI("http://url/tag");
|
||||
let uri10 = NetUtil.newURI("http://url/tag/2");
|
||||
let uri11 = NetUtil.newURI("http://foo.bar/tag");
|
||||
let uri12 = NetUtil.newURI("http://foo.bar/tag/2");
|
||||
yield promiseAddVisits([ { uri: uri1, title: "title", transition: TRANSITION_TYPED },
|
||||
{ uri: uri2, title: "foo.bar" },
|
||||
{ uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "foo.bar", transition: TRANSITION_TYPED },
|
||||
{ uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title", transition: TRANSITION_TYPED } ]);
|
||||
addBookmark( { uri: uri5, title: "title" } );
|
||||
addBookmark( { uri: uri6, title: "foo.bar" } );
|
||||
addBookmark( { uri: uri7, title: "title" } );
|
||||
addBookmark( { uri: uri8, title: "foo.bar" } );
|
||||
addBookmark( { uri: uri9, title: "title", tags: [ "foo.bar" ] } );
|
||||
addBookmark( { uri: uri10, title: "foo.bar", tags: [ "foo.bar" ] } );
|
||||
addBookmark( { uri: uri11, title: "title", tags: [ "foo.bar" ] } );
|
||||
addBookmark( { uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } );
|
||||
|
||||
// Test restricting searches
|
||||
do_log_info("History restrict");
|
||||
yield check_autocomplete({
|
||||
search: "^",
|
||||
matches: [ { uri: uri1, title: "title" },
|
||||
{ uri: uri2, title: "foo.bar" },
|
||||
{ uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("Star restrict");
|
||||
yield check_autocomplete({
|
||||
search: "*",
|
||||
matches: [ { uri: uri5, title: "title" },
|
||||
{ uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri7, title: "title" },
|
||||
{ uri: uri8, title: "foo.bar" },
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar"] },
|
||||
{ uri: uri12, title: "foo.bar", tags: ["foo.bar"] } ]
|
||||
});
|
||||
|
||||
do_log_info("Tag restrict");
|
||||
yield check_autocomplete({
|
||||
search: "+",
|
||||
matches: [ { uri: uri9, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
// Test specials as any word position
|
||||
do_log_info("Special as first word");
|
||||
yield check_autocomplete({
|
||||
search: "^ foo bar",
|
||||
matches: [ { uri: uri2, title: "foo.bar" },
|
||||
{ uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("Special as middle word");
|
||||
yield check_autocomplete({
|
||||
search: "foo ^ bar",
|
||||
matches: [ { uri: uri2, title: "foo.bar" },
|
||||
{ uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("Special as last word");
|
||||
yield check_autocomplete({
|
||||
search: "foo bar ^",
|
||||
matches: [ { uri: uri2, title: "foo.bar" },
|
||||
{ uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title" } ]
|
||||
});
|
||||
|
||||
// Test restricting and matching searches with a term
|
||||
do_log_info("foo ^ -> history");
|
||||
yield check_autocomplete({
|
||||
search: "foo ^",
|
||||
matches: [ { uri: uri2, title: "foo.bar" },
|
||||
{ uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("foo | -> history (change pref)");
|
||||
changeRestrict("history", "|");
|
||||
yield check_autocomplete({
|
||||
search: "foo |",
|
||||
matches: [ { uri: uri2, title: "foo.bar" },
|
||||
{ uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("foo * -> is star");
|
||||
resetRestrict("history");
|
||||
yield check_autocomplete({
|
||||
search: "foo *",
|
||||
matches: [ { uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri7, title: "title" },
|
||||
{ uri: uri8, title: "foo.bar" },
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo | -> is star (change pref)");
|
||||
changeRestrict("bookmark", "|");
|
||||
yield check_autocomplete({
|
||||
search: "foo |",
|
||||
matches: [ { uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri7, title: "title" },
|
||||
{ uri: uri8, title: "foo.bar" },
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo # -> in title");
|
||||
resetRestrict("bookmark");
|
||||
yield check_autocomplete({
|
||||
search: "foo #",
|
||||
matches: [ { uri: uri2, title: "foo.bar" },
|
||||
{ uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri8, title: "foo.bar" },
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo | -> in title (change pref)");
|
||||
changeRestrict("title", "|");
|
||||
yield check_autocomplete({
|
||||
search: "foo |",
|
||||
matches: [ { uri: uri2, title: "foo.bar" },
|
||||
{ uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri8, title: "foo.bar" },
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo @ -> in url");
|
||||
resetRestrict("title");
|
||||
yield check_autocomplete({
|
||||
search: "foo @",
|
||||
matches: [ { uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri7, title: "title" },
|
||||
{ uri: uri8, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo | -> in url (change pref)");
|
||||
changeRestrict("url", "|");
|
||||
yield check_autocomplete({
|
||||
search: "foo |",
|
||||
matches: [ { uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri7, title: "title" },
|
||||
{ uri: uri8, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo + -> is tag");
|
||||
resetRestrict("url");
|
||||
yield check_autocomplete({
|
||||
search: "foo +",
|
||||
matches: [ { uri: uri9, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo | -> is tag (change pref)");
|
||||
changeRestrict("tag", "|");
|
||||
yield check_autocomplete({
|
||||
search: "foo |",
|
||||
matches: [ { uri: uri9, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo ~ -> is typed");
|
||||
resetRestrict("tag");
|
||||
yield check_autocomplete({
|
||||
search: "foo ~",
|
||||
matches: [ { uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo | -> is typed (change pref)");
|
||||
changeRestrict("typed", "|");
|
||||
yield check_autocomplete({
|
||||
search: "foo |",
|
||||
matches: [ { uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
// Test various pairs of special searches
|
||||
do_log_info("foo ^ * -> history, is star");
|
||||
resetRestrict("typed");
|
||||
yield check_autocomplete({
|
||||
search: "foo ^ *",
|
||||
matches: [ { uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo ^ # -> history, in title");
|
||||
yield check_autocomplete({
|
||||
search: "foo ^ #",
|
||||
matches: [ { uri: uri2, title: "foo.bar" },
|
||||
{ uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("foo ^ @ -> history, in url");
|
||||
yield check_autocomplete({
|
||||
search: "foo ^ @",
|
||||
matches: [ { uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("foo ^ + -> history, is tag");
|
||||
yield check_autocomplete({
|
||||
search: "foo ^ +",
|
||||
matches: [ { uri: uri11, title: "title", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo ^ ~ -> history, is typed");
|
||||
yield check_autocomplete({
|
||||
search: "foo ^ ~",
|
||||
matches: [ { uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("foo * # -> is star, in title");
|
||||
yield check_autocomplete({
|
||||
search: "foo * #",
|
||||
matches: [ { uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri8, title: "foo.bar" },
|
||||
{ uri: uri9, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo * @ -> is star, in url");
|
||||
yield check_autocomplete({
|
||||
search: "foo * @",
|
||||
matches: [ { uri: uri7, title: "title" },
|
||||
{ uri: uri8, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo * + -> same as +");
|
||||
yield check_autocomplete({
|
||||
search: "foo * +",
|
||||
matches: [ { uri: uri9, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo * ~ -> is star, is typed");
|
||||
yield check_autocomplete({
|
||||
search: "foo * ~",
|
||||
matches: [ { uri: uri11, title: "title", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo # @ -> in title, in url");
|
||||
yield check_autocomplete({
|
||||
search: "foo # @",
|
||||
matches: [ { uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri8, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo # + -> in title, is tag");
|
||||
yield check_autocomplete({
|
||||
search: "foo # +",
|
||||
matches: [ { uri: uri9, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri10, title: "foo.bar", tags: [ "foo.bar" ] },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo # ~ -> in title, is typed");
|
||||
yield check_autocomplete({
|
||||
search: "foo # ~",
|
||||
matches: [ { uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo @ + -> in url, is tag");
|
||||
yield check_autocomplete({
|
||||
search: "foo @ +",
|
||||
matches: [ { uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo @ ~ -> in url, is typed");
|
||||
yield check_autocomplete({
|
||||
search: "foo @ ~",
|
||||
matches: [ { uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo + ~ -> is tag, is typed");
|
||||
yield check_autocomplete({
|
||||
search: "foo + ~",
|
||||
matches: [ { uri: uri11, title: "title", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
// 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);
|
||||
yield check_autocomplete({
|
||||
search: "foo",
|
||||
matches: [ { uri: uri2, title: "foo.bar" },
|
||||
{ uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("foo -> default history, is star");
|
||||
Services.prefs.setIntPref("browser.urlbar.default.behavior", 3);
|
||||
yield check_autocomplete({
|
||||
search: "foo",
|
||||
matches: [ { uri: uri6, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo -> default history, is star, is typed");
|
||||
Services.prefs.setIntPref("browser.urlbar.default.behavior", 35);
|
||||
yield check_autocomplete({
|
||||
search: "foo",
|
||||
matches: [ { uri: uri11, title: "title", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo -> default history, is star, in url");
|
||||
Services.prefs.setIntPref("browser.urlbar.default.behavior", 19);
|
||||
yield check_autocomplete({
|
||||
search: "foo",
|
||||
matches: [ { uri: uri11, title: "title", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
// Change the default to be less restrictive to make sure we find more
|
||||
do_log_info("foo -> default is star, in url");
|
||||
Services.prefs.setIntPref("browser.urlbar.default.behavior", 18);
|
||||
yield check_autocomplete({
|
||||
search: "foo",
|
||||
matches: [ { uri: uri7, title: "title" },
|
||||
{ uri: uri8, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("foo -> default in url");
|
||||
Services.prefs.setIntPref("browser.urlbar.default.behavior", 16);
|
||||
yield check_autocomplete({
|
||||
search: "foo",
|
||||
matches: [ { uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "foo.bar" },
|
||||
{ uri: uri7, title: "title" },
|
||||
{ uri: uri8, title: "foo.bar" },
|
||||
{ uri: uri11, title: "title", tags: [ "foo.bar" ] },
|
||||
{ uri: uri12, title: "foo.bar", tags: [ "foo.bar" ] } ]
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,149 @@
|
||||
/* 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 bug 424717 to make sure searching with an existing location like
|
||||
* http://site/ also matches https://site/ or ftp://site/. Same thing for
|
||||
* ftp://site/ and https://site/.
|
||||
*
|
||||
* Test bug 461483 to make sure a search for "w" doesn't match the "www." from
|
||||
* site subdomains.
|
||||
*/
|
||||
|
||||
add_task(function* test_swap_protocol() {
|
||||
let uri1 = NetUtil.newURI("http://www.site/");
|
||||
let uri2 = NetUtil.newURI("http://site/");
|
||||
let uri3 = NetUtil.newURI("ftp://ftp.site/");
|
||||
let uri4 = NetUtil.newURI("ftp://site/");
|
||||
let uri5 = NetUtil.newURI("https://www.site/");
|
||||
let uri6 = NetUtil.newURI("https://site/");
|
||||
let uri7 = NetUtil.newURI("http://woohoo/");
|
||||
let uri8 = NetUtil.newURI("http://wwwwwwacko/");
|
||||
yield promiseAddVisits([ { uri: uri1, title: "title" },
|
||||
{ uri: uri2, title: "title" },
|
||||
{ uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "title" },
|
||||
{ uri: uri5, title: "title" },
|
||||
{ uri: uri6, title: "title" },
|
||||
{ uri: uri7, title: "title" },
|
||||
{ uri: uri8, title: "title" } ]);
|
||||
|
||||
let allMatches = [
|
||||
{ uri: uri1, title: "title" },
|
||||
{ uri: uri2, title: "title" },
|
||||
{ uri: uri3, title: "title" },
|
||||
{ uri: uri4, title: "title" },
|
||||
{ uri: uri5, title: "title" },
|
||||
{ uri: uri6, title: "title" }
|
||||
];
|
||||
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill", "false");
|
||||
|
||||
do_log_info("http://www.site matches all site");
|
||||
yield check_autocomplete({
|
||||
search: "http://www.site",
|
||||
matches: allMatches
|
||||
});
|
||||
/*
|
||||
do_log_info("http://site matches all site");
|
||||
yield check_autocomplete({
|
||||
search: "http://site",
|
||||
matches: allMatches
|
||||
});
|
||||
|
||||
do_log_info("ftp://ftp.site matches itself");
|
||||
yield check_autocomplete({
|
||||
search: "ftp://ftp.site",
|
||||
matches: { uri: uri3, title: "title"}
|
||||
});
|
||||
|
||||
do_log_info("ftp://site matches all site");
|
||||
yield check_autocomplete({
|
||||
search: "ftp://site",
|
||||
matches: allMatches
|
||||
});
|
||||
|
||||
do_log_info("https://www.site matches all site");
|
||||
yield check_autocomplete({
|
||||
search: "https://www.site",
|
||||
matches: allMatches
|
||||
});
|
||||
|
||||
do_log_info("https://site matches all site");
|
||||
yield check_autocomplete({
|
||||
search: "https://site",
|
||||
matches: allMatches
|
||||
});
|
||||
|
||||
do_log_info("www.site matches all site");
|
||||
yield check_autocomplete({
|
||||
search: "www.site",
|
||||
matches: allMatches
|
||||
});
|
||||
|
||||
do_log_info("w matches none of www.");
|
||||
yield check_autocomplete({
|
||||
search: "w",
|
||||
matches: [ { uri: uri7, title: "title" },
|
||||
{ uri: uri8, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("http://w matches none of www.");
|
||||
yield check_autocomplete({
|
||||
search: "http://w",
|
||||
matches: [ { uri: uri7, title: "title" },
|
||||
{ uri: uri8, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("http://w matches none of www.");
|
||||
yield check_autocomplete({
|
||||
search: "http://www.w",
|
||||
matches: [ { uri: uri7, title: "title" },
|
||||
{ uri: uri8, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("ww matches none of www.");
|
||||
yield check_autocomplete({
|
||||
search: "ww",
|
||||
matches: [ { uri: uri8, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("ww matches none of www.");
|
||||
yield check_autocomplete({
|
||||
search: "ww",
|
||||
matches: [ { uri: uri8, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("http://ww matches none of www.");
|
||||
yield check_autocomplete({
|
||||
search: "http://ww",
|
||||
matches: [ { uri: uri8, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("http://www.ww matches none of www.");
|
||||
yield check_autocomplete({
|
||||
search: "http://www.ww",
|
||||
matches: [ { uri: uri8, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("www matches none of www.");
|
||||
yield check_autocomplete({
|
||||
search: "www",
|
||||
matches: [ { uri: uri8, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("http://www matches none of www.");
|
||||
yield check_autocomplete({
|
||||
search: "http://www",
|
||||
matches: [ { uri: uri8, title: "title" } ]
|
||||
});
|
||||
|
||||
do_log_info("http://www.www matches none of www.");
|
||||
yield check_autocomplete({
|
||||
search: "http://www.www",
|
||||
matches: [ { uri: uri8, title: "title" } ]
|
||||
});
|
||||
*/
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,96 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */
|
||||
|
||||
let gTabRestrictChar = "%";
|
||||
|
||||
add_task(function* test_tab_matches() {
|
||||
let uri1 = NetUtil.newURI("http://abc.com/");
|
||||
let uri2 = NetUtil.newURI("http://xyz.net/");
|
||||
let uri3 = NetUtil.newURI("about:mozilla");
|
||||
let uri4 = NetUtil.newURI("data:text/html,test");
|
||||
yield promiseAddVisits([ { uri: uri1, title: "ABC rocks" },
|
||||
{ uri: uri2, title: "xyz.net - we're better than ABC" } ]);
|
||||
addOpenPages(uri1, 1);
|
||||
// Pages that cannot be registered in history.
|
||||
addOpenPages(uri3, 1);
|
||||
addOpenPages(uri4, 1);
|
||||
|
||||
do_log_info("single result, that is also a tab match");
|
||||
yield check_autocomplete({
|
||||
search: "abc.com",
|
||||
searchParam: "enable-actions",
|
||||
matches: [ { uri: NetUtil.newURI("moz-action:switchtab,http://abc.com/"), title: "ABC rocks" } ]
|
||||
});
|
||||
|
||||
do_log_info("two results, one tab match");
|
||||
yield check_autocomplete({
|
||||
search: "abc",
|
||||
searchParam: "enable-actions",
|
||||
matches: [ { uri: NetUtil.newURI("moz-action:switchtab,http://abc.com/"), title: "ABC rocks" },
|
||||
{ uri: uri2, title: "xyz.net - we're better than ABC" } ]
|
||||
});
|
||||
|
||||
do_log_info("two results, both tab matches");
|
||||
addOpenPages(uri2, 1);
|
||||
yield check_autocomplete({
|
||||
search: "abc",
|
||||
searchParam: "enable-actions",
|
||||
matches: [ { uri: NetUtil.newURI("moz-action:switchtab,http://abc.com/"), title: "ABC rocks" },
|
||||
{ uri: NetUtil.newURI("moz-action:switchtab,http://xyz.net/"), title: "xyz.net - we're better than ABC" } ]
|
||||
});
|
||||
|
||||
do_log_info("two results, both tab matches, one has multiple tabs");
|
||||
addOpenPages(uri2, 5);
|
||||
yield check_autocomplete({
|
||||
search: "abc",
|
||||
searchParam: "enable-actions",
|
||||
matches: [ { uri: NetUtil.newURI("moz-action:switchtab,http://abc.com/"), title: "ABC rocks" },
|
||||
{ uri: NetUtil.newURI("moz-action:switchtab,http://xyz.net/"), title: "xyz.net - we're better than ABC" } ]
|
||||
});
|
||||
|
||||
do_log_info("two results, no tab matches");
|
||||
removeOpenPages(uri1, 1);
|
||||
removeOpenPages(uri2, 6);
|
||||
yield check_autocomplete({
|
||||
search: "abc",
|
||||
searchParam: "enable-actions",
|
||||
matches: [ { uri: uri1, title: "ABC rocks" },
|
||||
{ uri: uri2, title: "xyz.net - we're better than ABC" } ]
|
||||
});
|
||||
|
||||
do_log_info("tab match search with restriction character");
|
||||
addOpenPages(uri1, 1);
|
||||
yield check_autocomplete({
|
||||
search: gTabRestrictChar + " abc",
|
||||
searchParam: "enable-actions",
|
||||
matches: [ { uri: NetUtil.newURI("moz-action:switchtab,http://abc.com/"), title: "ABC rocks" } ]
|
||||
});
|
||||
|
||||
do_log_info("tab match with not-addable pages");
|
||||
yield check_autocomplete({
|
||||
search: "mozilla",
|
||||
searchParam: "enable-actions",
|
||||
matches: [ { uri: NetUtil.newURI("moz-action:switchtab,about:mozilla"), title: "about:mozilla" } ]
|
||||
});
|
||||
|
||||
do_log_info("tab match with not-addable pages and restriction character");
|
||||
yield check_autocomplete({
|
||||
search: gTabRestrictChar + " mozilla",
|
||||
searchParam: "enable-actions",
|
||||
matches: [ { uri: NetUtil.newURI("moz-action:switchtab,about:mozilla"), title: "about:mozilla" } ]
|
||||
});
|
||||
|
||||
do_log_info("tab match with not-addable pages and only restriction character");
|
||||
yield check_autocomplete({
|
||||
search: gTabRestrictChar,
|
||||
searchParam: "enable-actions",
|
||||
matches: [ { uri: NetUtil.newURI("moz-action:switchtab,http://abc.com/"), title: "ABC rocks" },
|
||||
{ uri: NetUtil.newURI("moz-action:switchtab,about:mozilla"), title: "about:mozilla" },
|
||||
{ uri: NetUtil.newURI("moz-action:switchtab,data:text/html,test"), title: "data:text/html,test" } ]
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
298
toolkit/components/places/tests/unifiedcomplete/test_trimming.js
Normal file
298
toolkit/components/places/tests/unifiedcomplete/test_trimming.js
Normal file
@ -0,0 +1,298 @@
|
||||
/* 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_untrimmed_secure_www() {
|
||||
do_log_info("Searching for untrimmed https://www entry");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("https://www.mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mo",
|
||||
autofilled: "mozilla.org/",
|
||||
completed: "https://www.mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untrimmed_secure_www_path() {
|
||||
do_log_info("Searching for untrimmed https://www entry with path");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("https://www.mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mozilla.org/t",
|
||||
autofilled: "mozilla.org/test/",
|
||||
completed: "https://www.mozilla.org/test/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untrimmed_secure() {
|
||||
do_log_info("Searching for untrimmed https:// entry");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("https://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mo",
|
||||
autofilled: "mozilla.org/",
|
||||
completed: "https://mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untrimmed_secure_path() {
|
||||
do_log_info("Searching for untrimmed https:// entry with path");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("https://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mozilla.org/t",
|
||||
autofilled: "mozilla.org/test/",
|
||||
completed: "https://mozilla.org/test/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untrimmed_www() {
|
||||
do_log_info("Searching for untrimmed http://www entry");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://www.mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mo",
|
||||
autofilled: "mozilla.org/",
|
||||
completed: "www.mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untrimmed_www_path() {
|
||||
do_log_info("Searching for untrimmed http://www entry with path");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://www.mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mozilla.org/t",
|
||||
autofilled: "mozilla.org/test/",
|
||||
completed: "http://www.mozilla.org/test/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untrimmed_ftp() {
|
||||
do_log_info("Searching for untrimmed ftp:// entry");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("ftp://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mo",
|
||||
autofilled: "mozilla.org/",
|
||||
completed: "ftp://mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untrimmed_ftp_path() {
|
||||
do_log_info("Searching for untrimmed ftp:// entry with path");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("ftp://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mozilla.org/t",
|
||||
autofilled: "mozilla.org/test/",
|
||||
completed: "ftp://mozilla.org/test/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_priority_1() {
|
||||
do_log_info("Ensuring correct priority 1");
|
||||
yield promiseAddVisits([{ uri: NetUtil.newURI("https://www.mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("https://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("ftp://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("http://www.mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("http://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED }]);
|
||||
yield check_autocomplete({
|
||||
search: "mo",
|
||||
autofilled: "mozilla.org/",
|
||||
completed: "mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_periority_2() {
|
||||
do_log_info( "Ensuring correct priority 2");
|
||||
yield promiseAddVisits([{ uri: NetUtil.newURI("https://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("ftp://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("http://www.mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("http://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED }]);
|
||||
yield check_autocomplete({
|
||||
search: "mo",
|
||||
autofilled: "mozilla.org/",
|
||||
completed: "mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_periority_3() {
|
||||
do_log_info("Ensuring correct priority 3");
|
||||
yield promiseAddVisits([{ uri: NetUtil.newURI("ftp://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("http://www.mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("http://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED }]);
|
||||
yield check_autocomplete({
|
||||
search: "mo",
|
||||
autofilled: "mozilla.org/",
|
||||
completed: "mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_periority_4() {
|
||||
do_log_info("Ensuring correct priority 4");
|
||||
yield promiseAddVisits([{ uri: NetUtil.newURI("http://www.mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("http://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED }]);
|
||||
yield check_autocomplete({
|
||||
search: "mo",
|
||||
autofilled: "mozilla.org/",
|
||||
completed: "mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_priority_5() {
|
||||
do_log_info("Ensuring correct priority 5");
|
||||
yield promiseAddVisits([{ uri: NetUtil.newURI("ftp://mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("ftp://www.mozilla.org/test/"),
|
||||
transition: TRANSITION_TYPED }]);
|
||||
yield check_autocomplete({
|
||||
search: "mo",
|
||||
autofilled: "mozilla.org/",
|
||||
completed: "ftp://mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_priority_6() {
|
||||
do_log_info("Ensuring correct priority 6");
|
||||
yield promiseAddVisits([{ uri: NetUtil.newURI("http://www.mozilla.org/test1/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("http://www.mozilla.org/test2/"),
|
||||
transition: TRANSITION_TYPED }]);
|
||||
yield check_autocomplete({
|
||||
search: "mo",
|
||||
autofilled: "mozilla.org/",
|
||||
completed: "www.mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_longer_domain() {
|
||||
do_log_info("Ensuring longer domain can't match");
|
||||
// The .co should be preferred, but should not get the https from the .com.
|
||||
// The .co domain must be added later to activate the trigger bug.
|
||||
yield promiseAddVisits([{ uri: NetUtil.newURI("https://mozilla.com/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("http://mozilla.co/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("http://mozilla.co/"),
|
||||
transition: TRANSITION_TYPED }]);
|
||||
yield check_autocomplete({
|
||||
search: "mo",
|
||||
autofilled: "mozilla.co/",
|
||||
completed: "mozilla.co/"
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_escaped_chars() {
|
||||
do_log_info("Searching for URL with characters that are normally escaped");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("https://www.mozilla.org/啊-test"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "https://www.mozilla.org/啊-test",
|
||||
autofilled: "https://www.mozilla.org/啊-test",
|
||||
completed: "https://www.mozilla.org/啊-test"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_unsecure_secure() {
|
||||
do_log_info("Don't return unsecure URL when searching for secure ones");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://test.moz.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "https://test.moz.org/t",
|
||||
autofilled: "https://test.moz.org/test/",
|
||||
completed: "https://test.moz.org/test/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_unsecure_secure_domain() {
|
||||
do_log_info("Don't return unsecure domain when searching for secure ones");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://test.moz.org/test/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "https://test.moz",
|
||||
autofilled: "https://test.moz.org/",
|
||||
completed: "https://test.moz.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untyped_www() {
|
||||
do_log_info("Untyped is not accounted for www");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://www.moz.org/test/") });
|
||||
yield check_autocomplete({
|
||||
search: "mo",
|
||||
autofilled: "moz.org/",
|
||||
completed: "moz.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untyped_ftp() {
|
||||
do_log_info("Untyped is not accounted for ftp");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("ftp://moz.org/test/") });
|
||||
yield check_autocomplete({
|
||||
search: "mo",
|
||||
autofilled: "moz.org/",
|
||||
completed: "moz.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untyped_secure() {
|
||||
do_log_info("Untyped is not accounted for https");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("https://moz.org/test/") });
|
||||
yield check_autocomplete({
|
||||
search: "mo",
|
||||
autofilled: "moz.org/",
|
||||
completed: "moz.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untyped_secure_www() {
|
||||
do_log_info("Untyped is not accounted for https://www");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("https://www.moz.org/test/") });
|
||||
yield check_autocomplete({
|
||||
search: "mo",
|
||||
autofilled: "moz.org/",
|
||||
completed: "moz.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,78 @@
|
||||
/* 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/. */
|
||||
|
||||
// First do searches with typed behavior forced to false, so later tests will
|
||||
// ensure autocomplete is able to dinamically switch behavior.
|
||||
|
||||
add_task(function* test_domain() {
|
||||
do_log_info("Searching for domain should autoFill it");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
yield promiseAddVisits(NetUtil.newURI("http://mozilla.org/link/"));
|
||||
yield check_autocomplete({
|
||||
search: "moz",
|
||||
autofilled: "mozilla.org/",
|
||||
completed: "mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_url() {
|
||||
do_log_info("Searching for url should autoFill it");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
yield promiseAddVisits(NetUtil.newURI("http://mozilla.org/link/"));
|
||||
yield check_autocomplete({
|
||||
search: "mozilla.org/li",
|
||||
autofilled: "mozilla.org/link/",
|
||||
completed: "http://mozilla.org/link/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
// Now do searches with typed behavior forced to true.
|
||||
|
||||
add_task(function* test_untyped_domain() {
|
||||
do_log_info("Searching for non-typed domain should not autoFill it");
|
||||
yield promiseAddVisits(NetUtil.newURI("http://mozilla.org/link/"));
|
||||
yield check_autocomplete({
|
||||
search: "moz",
|
||||
autofilled: "moz",
|
||||
completed: "moz"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_typed_domain() {
|
||||
do_log_info("Searching for typed domain should autoFill it");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/typed/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "moz",
|
||||
autofilled: "mozilla.org/",
|
||||
completed: "mozilla.org/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_untyped_url() {
|
||||
do_log_info("Searching for non-typed url should not autoFill it");
|
||||
yield promiseAddVisits(NetUtil.newURI("http://mozilla.org/link/"));
|
||||
yield check_autocomplete({
|
||||
search: "mozilla.org/li",
|
||||
autofilled: "mozilla.org/li",
|
||||
completed: "mozilla.org/li"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_typed_url() {
|
||||
do_log_info("Searching for typed url should autoFill it");
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/link/"),
|
||||
transition: TRANSITION_TYPED });
|
||||
yield check_autocomplete({
|
||||
search: "mozilla.org/li",
|
||||
autofilled: "mozilla.org/link/",
|
||||
completed: "http://mozilla.org/link/"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,171 @@
|
||||
/* 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 bug 393678 to make sure matches against the url, title, tags are only
|
||||
* made on word boundaries instead of in the middle of words.
|
||||
*
|
||||
* Make sure we don't try matching one after a CamelCase because the upper-case
|
||||
* isn't really a word boundary. (bug 429498)
|
||||
*
|
||||
* Bug 429531 provides switching between "must match on word boundary" and "can
|
||||
* match," so leverage "must match" pref for checking word boundary logic and
|
||||
* make sure "can match" matches anywhere.
|
||||
*/
|
||||
|
||||
let katakana = ["\u30a8", "\u30c9"]; // E, Do
|
||||
let ideograph = ["\u4efb", "\u5929", "\u5802"]; // Nin Ten Do
|
||||
|
||||
add_task(function* test_escape() {
|
||||
let uri1 = NetUtil.newURI("http://matchme/");
|
||||
let uri2 = NetUtil.newURI("http://dontmatchme/");
|
||||
let uri3 = NetUtil.newURI("http://title/1");
|
||||
let uri4 = NetUtil.newURI("http://title/2");
|
||||
let uri5 = NetUtil.newURI("http://tag/1");
|
||||
let uri6 = NetUtil.newURI("http://tag/2");
|
||||
let uri7 = NetUtil.newURI("http://crazytitle/");
|
||||
let uri8 = NetUtil.newURI("http://katakana/");
|
||||
let uri9 = NetUtil.newURI("http://ideograph/");
|
||||
let uri10 = NetUtil.newURI("http://camel/pleaseMatchMe/");
|
||||
|
||||
yield promiseAddVisits([ { uri: uri1, title: "title1" },
|
||||
{ uri: uri2, title: "title1" },
|
||||
{ uri: uri3, title: "matchme2" },
|
||||
{ uri: uri4, title: "dontmatchme3" },
|
||||
{ uri: uri5, title: "title1" },
|
||||
{ uri: uri6, title: "title1" },
|
||||
{ uri: uri7, title: "!@#$%^&*()_+{}|:<>?word" },
|
||||
{ uri: uri8, title: katakana.join("") },
|
||||
{ uri: uri9, title: ideograph.join("") },
|
||||
{ uri: uri10, title: "title1" } ]);
|
||||
addBookmark( { uri: uri5, title: "title1", tags: [ "matchme2" ] } );
|
||||
addBookmark( { uri: uri6, title: "title1", tags: [ "dontmatchme3" ] } );
|
||||
|
||||
// match only on word boundaries
|
||||
Services.prefs.setIntPref("browser.urlbar.matchBehavior", 2);
|
||||
|
||||
do_log_info("Match 'match' at the beginning or after / or on a CamelCase");
|
||||
yield check_autocomplete({
|
||||
search: "match",
|
||||
matches: [ { uri: uri1, title: "title1" },
|
||||
{ uri: uri3, title: "matchme2" },
|
||||
{ uri: uri5, title: "title1", tags: [ "matchme2" ] },
|
||||
{ uri: uri10, title: "title1" } ]
|
||||
});
|
||||
|
||||
do_log_info("Match 'dont' at the beginning or after /");
|
||||
yield check_autocomplete({
|
||||
search: "dont",
|
||||
matches: [ { uri: uri2, title: "title1" },
|
||||
{ uri: uri4, title: "dontmatchme3" },
|
||||
{ uri: uri6, title: "title1", tags: [ "dontmatchme3" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("Match 'match' at the beginning or after / or on a CamelCase");
|
||||
yield check_autocomplete({
|
||||
search: "2",
|
||||
matches: [ { uri: uri3, title: "matchme2" },
|
||||
{ uri: uri4, title: "dontmatchme3" },
|
||||
{ uri: uri5, title: "title1", tags: [ "matchme2" ] },
|
||||
{ uri: uri6, title: "title1", tags: [ "dontmatchme3" ] } ]
|
||||
});
|
||||
|
||||
do_log_info("Match 't' at the beginning or after /");
|
||||
yield check_autocomplete({
|
||||
search: "t",
|
||||
matches: [ { uri: uri1, title: "title1" },
|
||||
{ uri: uri2, title: "title1" },
|
||||
{ uri: uri3, title: "matchme2" },
|
||||
{ uri: uri4, title: "dontmatchme3" },
|
||||
{ uri: uri5, title: "title1", tags: [ "matchme2" ] },
|
||||
{ uri: uri6, title: "title1", tags: [ "dontmatchme3" ] },
|
||||
{ uri: uri10, title: "title1" } ]
|
||||
});
|
||||
|
||||
do_log_info("Match 'word' after many consecutive word boundaries");
|
||||
yield check_autocomplete({
|
||||
search: "word",
|
||||
matches: [ { uri: uri7, title: "!@#$%^&*()_+{}|:<>?word" } ]
|
||||
});
|
||||
|
||||
do_log_info("Match a word boundary '/' for everything");
|
||||
yield check_autocomplete({
|
||||
search: "/",
|
||||
matches: [ { uri: uri1, title: "title1" },
|
||||
{ uri: uri2, title: "title1" },
|
||||
{ uri: uri3, title: "matchme2" },
|
||||
{ uri: uri4, title: "dontmatchme3" },
|
||||
{ uri: uri5, title: "title1", tags: [ "matchme2" ] },
|
||||
{ uri: uri6, title: "title1", tags: [ "dontmatchme3" ] },
|
||||
{ uri: uri7, title: "!@#$%^&*()_+{}|:<>?word" },
|
||||
{ uri: uri8, title: katakana.join("") },
|
||||
{ uri: uri9, title: ideograph.join("") },
|
||||
{ uri: uri10, title: "title1" } ]
|
||||
});
|
||||
|
||||
do_log_info("Match word boundaries '()_+' that are among word boundaries");
|
||||
yield check_autocomplete({
|
||||
search: "()_+",
|
||||
matches: [ { uri: uri7, title: "!@#$%^&*()_+{}|:<>?word" } ]
|
||||
});
|
||||
|
||||
do_log_info("Katakana characters form a string, so match the beginning");
|
||||
yield check_autocomplete({
|
||||
search: katakana[0],
|
||||
matches: [ { uri: uri8, title: katakana.join("") } ]
|
||||
});
|
||||
|
||||
/*
|
||||
do_log_info("Middle of a katakana word shouldn't be matched");
|
||||
yield check_autocomplete({
|
||||
search: katakana[1],
|
||||
matches: [ ]
|
||||
});
|
||||
*/
|
||||
do_log_info("Ideographs are treated as words so 'nin' is one word");
|
||||
yield check_autocomplete({
|
||||
search: ideograph[0],
|
||||
matches: [ { uri: uri9, title: ideograph.join("") } ]
|
||||
});
|
||||
|
||||
do_log_info("Ideographs are treated as words so 'ten' is another word");
|
||||
yield check_autocomplete({
|
||||
search: ideograph[1],
|
||||
matches: [ { uri: uri9, title: ideograph.join("") } ]
|
||||
});
|
||||
|
||||
do_log_info("Ideographs are treated as words so 'do' is yet another word");
|
||||
yield check_autocomplete({
|
||||
search: ideograph[2],
|
||||
matches: [ { uri: uri9, title: ideograph.join("") } ]
|
||||
});
|
||||
|
||||
do_log_info("Extra negative assert that we don't match in the middle");
|
||||
yield check_autocomplete({
|
||||
search: "ch",
|
||||
matches: [ ]
|
||||
});
|
||||
|
||||
do_log_info("Don't match one character after a camel-case word boundary (bug 429498)");
|
||||
yield check_autocomplete({
|
||||
search: "atch",
|
||||
matches: [ ]
|
||||
});
|
||||
|
||||
// match against word boundaries and anywhere
|
||||
Services.prefs.setIntPref("browser.urlbar.matchBehavior", 1);
|
||||
|
||||
yield check_autocomplete({
|
||||
search: "tch",
|
||||
matches: [ { uri: uri1, title: "title1" },
|
||||
{ uri: uri2, title: "title1" },
|
||||
{ uri: uri3, title: "matchme2" },
|
||||
{ uri: uri4, title: "dontmatchme3" },
|
||||
{ uri: uri5, title: "title1", tags: [ "matchme2" ] },
|
||||
{ uri: uri6, title: "title1", tags: [ "dontmatchme3" ] },
|
||||
{ uri: uri10, title: "title1" } ]
|
||||
});
|
||||
|
||||
yield cleanup();
|
||||
});
|
@ -0,0 +1,31 @@
|
||||
/* 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/. */
|
||||
|
||||
// Ensure inline autocomplete doesn't return zero frecency pages.
|
||||
|
||||
add_task(function* test_zzero_frec_domain() {
|
||||
do_log_info("Searching for zero frecency domain should not autoFill it");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/framed_link/"),
|
||||
transition: TRANSITION_FRAMED_LINK });
|
||||
yield check_autocomplete({
|
||||
search: "moz",
|
||||
autofilled: "moz",
|
||||
completed: "moz"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_zzero_frec_url() {
|
||||
do_log_info("Searching for zero frecency url should not autoFill it");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
|
||||
yield promiseAddVisits({ uri: NetUtil.newURI("http://mozilla.org/framed_link/"),
|
||||
transition: TRANSITION_FRAMED_LINK });
|
||||
yield check_autocomplete({
|
||||
search: "mozilla.org/f",
|
||||
autofilled: "mozilla.org/f",
|
||||
completed: "mozilla.org/f"
|
||||
});
|
||||
yield cleanup();
|
||||
});
|
31
toolkit/components/places/tests/unifiedcomplete/xpcshell.ini
Normal file
31
toolkit/components/places/tests/unifiedcomplete/xpcshell.ini
Normal file
@ -0,0 +1,31 @@
|
||||
[DEFAULT]
|
||||
head = head_autocomplete.js
|
||||
tail =
|
||||
|
||||
[test_416211.js]
|
||||
[test_416214.js]
|
||||
[test_417798.js]
|
||||
[test_418257.js]
|
||||
[test_422277.js]
|
||||
[test_autocomplete_functional.js]
|
||||
[test_autocomplete_on_value_removed_479089.js]
|
||||
[test_casing.js]
|
||||
[test_do_not_trim.js]
|
||||
[test_download_embed_bookmarks.js]
|
||||
[test_dupe_urls.js]
|
||||
[test_empty_search.js]
|
||||
[test_enabled.js]
|
||||
[test_escape_self.js]
|
||||
[test_ignore_protocol.js]
|
||||
[test_keyword_search.js]
|
||||
[test_keywords.js]
|
||||
[test_match_beginning.js]
|
||||
[test_multi_word_search.js]
|
||||
[test_queryurl.js]
|
||||
[test_special_search.js]
|
||||
[test_swap_protocol.js]
|
||||
[test_tabmatches.js]
|
||||
[test_trimming.js]
|
||||
[test_typed.js]
|
||||
[test_word_boundary_search.js]
|
||||
[test_zero_frecency.js]
|
@ -151,23 +151,11 @@ XPCOMUtils.defineLazyGetter(SocialServiceInternal, "providers", function () {
|
||||
});
|
||||
|
||||
function getOriginActivationType(origin) {
|
||||
// access from moz-safe-about scheme will throw exception in getManifestPrefname
|
||||
try {
|
||||
var prefname = SocialServiceInternal.getManifestPrefname(origin);
|
||||
} catch(e) {
|
||||
// if this is an about uri, treat it as a directory
|
||||
let originUri = Services.io.newURI(origin, null, null);
|
||||
if (originUri.scheme == "moz-safe-about") {
|
||||
return "internal";
|
||||
}
|
||||
throw e;
|
||||
// if this is an about uri, treat it as a directory
|
||||
let originUri = Services.io.newURI(origin, null, null);
|
||||
if (originUri.scheme == "moz-safe-about") {
|
||||
return "internal";
|
||||
}
|
||||
if (Services.prefs.getDefaultBranch("social.manifest.").getPrefType(prefname) == Services.prefs.PREF_STRING)
|
||||
return 'builtin';
|
||||
|
||||
let whitelist = Services.prefs.getCharPref("social.whitelist").split(',');
|
||||
if (whitelist.indexOf(origin) >= 0)
|
||||
return 'whitelist';
|
||||
|
||||
let directories = Services.prefs.getCharPref("social.directories").split(',');
|
||||
if (directories.indexOf(origin) >= 0)
|
||||
@ -380,10 +368,11 @@ this.SocialService = {
|
||||
throw new Error("not allowed to set SocialService.enabled");
|
||||
},
|
||||
|
||||
// Adds and activates a builtin provider. The provider may or may not have
|
||||
// previously been added. onDone is always called - with null if no such
|
||||
// provider exists, or the activated provider on success.
|
||||
addBuiltinProvider: function addBuiltinProvider(origin, onDone) {
|
||||
// Enables a provider, the manifest must already exist in prefs. The provider
|
||||
// may or may not have previously been added. onDone is always called
|
||||
// - with null if no such provider exists, or the activated provider on
|
||||
// success.
|
||||
enableProvider: function enableProvider(origin, onDone) {
|
||||
if (SocialServiceInternal.providers[origin]) {
|
||||
schedule(function() {
|
||||
onDone(SocialServiceInternal.providers[origin]);
|
||||
@ -425,9 +414,9 @@ this.SocialService = {
|
||||
|
||||
// Removes a provider with the given origin, and notifies when the removal is
|
||||
// complete.
|
||||
removeProvider: function removeProvider(origin, onDone) {
|
||||
disableProvider: function disableProvider(origin, onDone) {
|
||||
if (!(origin in SocialServiceInternal.providers))
|
||||
throw new Error("SocialService.removeProvider: no provider with origin " + origin + " exists!");
|
||||
throw new Error("SocialService.disableProvider: no provider with origin " + origin + " exists!");
|
||||
|
||||
let provider = SocialServiceInternal.providers[origin];
|
||||
let manifest = SocialService.getManifestByOrigin(origin);
|
||||
@ -527,8 +516,6 @@ this.SocialService = {
|
||||
data.origin = principal.origin;
|
||||
|
||||
// iconURL and name are required
|
||||
// iconURL may be a different origin (CDN or data url support) if this is
|
||||
// a whitelisted or directory listed provider
|
||||
let providerHasFeatures = [url for (url of featureURLs) if (data[url])].length > 0;
|
||||
if (!providerHasFeatures) {
|
||||
Cu.reportError("SocialService.manifestFromData manifest missing required urls.");
|
||||
@ -650,23 +637,6 @@ this.SocialService = {
|
||||
installer = new AddonInstaller(sourceURI, manifest, installCallback);
|
||||
this._showInstallNotification(aDOMDocument, installer);
|
||||
break;
|
||||
case "builtin":
|
||||
// for builtin, we already have a manifest, but it can be overridden
|
||||
// we need to return the manifest in the installcallback, so fetch
|
||||
// it if we have it. If there is no manifest data for the builtin,
|
||||
// the install request MUST be from the provider, otherwise we have
|
||||
// no way to know what provider we're trying to enable. This is
|
||||
// primarily an issue for "version zero" providers that did not
|
||||
// send the manifest with the dom event for activation.
|
||||
if (!manifest) {
|
||||
let prefname = getPrefnameFromOrigin(installOrigin);
|
||||
manifest = Services.prefs.getDefaultBranch(null)
|
||||
.getComplexValue(prefname, Ci.nsISupportsString).data;
|
||||
manifest = JSON.parse(manifest);
|
||||
// ensure we override a builtin manifest by having a different value in it
|
||||
if (manifest.builtin)
|
||||
delete manifest.builtin;
|
||||
}
|
||||
case "internal":
|
||||
// double check here since "builtin" falls through this as well.
|
||||
aBypassUserEnable = installType == "internal" && manifest.oneclick;
|
||||
@ -678,8 +648,6 @@ this.SocialService = {
|
||||
installer.install();
|
||||
return;
|
||||
}
|
||||
// otherwise fall through to the install below which presents the panel
|
||||
case "whitelist":
|
||||
// a manifest is required, we'll catch a missing manifest below.
|
||||
if (!manifest)
|
||||
throw new Error("Cannot install provider without manifest data");
|
||||
@ -774,9 +742,10 @@ function SocialProvider(input) {
|
||||
this.errorState = null;
|
||||
this.frecency = 0;
|
||||
|
||||
let activationType = getOriginActivationType(input.origin);
|
||||
this.blessed = activationType == "builtin" ||
|
||||
activationType == "whitelist";
|
||||
// this provider has localStorage access in the worker if listed in the
|
||||
// whitelist
|
||||
let whitelist = Services.prefs.getCharPref("social.whitelist").split(',');
|
||||
this.blessed = whitelist.indexOf(this.origin) >= 0;
|
||||
|
||||
try {
|
||||
this.domain = etld.getBaseDomainFromHost(originUri.host);
|
||||
@ -1055,7 +1024,7 @@ var SocialAddonProvider = {
|
||||
if (ActiveProviders.has(manifest.origin)) {
|
||||
let addon = new AddonWrapper(manifest);
|
||||
if (addon.blocklistState != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
|
||||
SocialService.removeProvider(manifest.origin);
|
||||
SocialService.disableProvider(manifest.origin);
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
@ -1252,9 +1221,9 @@ AddonWrapper.prototype = {
|
||||
if (val == this.userDisabled)
|
||||
return val;
|
||||
if (val) {
|
||||
SocialService.removeProvider(this.manifest.origin);
|
||||
SocialService.disableProvider(this.manifest.origin);
|
||||
} else if (!this.appDisabled) {
|
||||
SocialService.addBuiltinProvider(this.manifest.origin);
|
||||
SocialService.enableProvider(this.manifest.origin);
|
||||
}
|
||||
return val;
|
||||
},
|
||||
@ -1263,7 +1232,7 @@ AddonWrapper.prototype = {
|
||||
let prefName = getPrefnameFromOrigin(this.manifest.origin);
|
||||
if (Services.prefs.prefHasUserValue(prefName)) {
|
||||
if (ActiveProviders.has(this.manifest.origin)) {
|
||||
SocialService.removeProvider(this.manifest.origin, function() {
|
||||
SocialService.disableProvider(this.manifest.origin, function() {
|
||||
SocialAddonProvider.removeAddon(this, aCallback);
|
||||
}.bind(this));
|
||||
} else {
|
||||
|
@ -16,7 +16,7 @@ function test() {
|
||||
SocialService.addProvider(manifest, function (p) {
|
||||
provider = p;
|
||||
runTests(tests, undefined, undefined, function () {
|
||||
SocialService.removeProvider(p.origin, function() {
|
||||
SocialService.disableProvider(p.origin, function() {
|
||||
ok(!provider.enabled, "removing an enabled provider should have disabled the provider");
|
||||
let port = provider.getWorkerPort();
|
||||
ok(!port, "should not be able to get a port after removing the provider");
|
||||
@ -74,7 +74,7 @@ let tests = {
|
||||
port2.onmessage = function(e) {
|
||||
if (e.data.topic == "test-initialization-complete") {
|
||||
ok(true, "second provider initialized");
|
||||
SocialService.removeProvider(provider2.origin, function() {
|
||||
SocialService.disableProvider(provider2.origin, function() {
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let cbPostTest = function(cb) {
|
||||
SocialService.removeProvider(TEST_PROVIDER_ORIGIN, function() {cb()});
|
||||
SocialService.disableProvider(TEST_PROVIDER_ORIGIN, function() {cb()});
|
||||
};
|
||||
replaceAlertsService();
|
||||
registerCleanupFunction(restoreAlertsService);
|
||||
|
@ -22,7 +22,7 @@ function test() {
|
||||
p.enabled = true;
|
||||
provider = p;
|
||||
runTests(tests, undefined, undefined, function () {
|
||||
SocialService.removeProvider(provider.origin, finish);
|
||||
SocialService.disableProvider(provider.origin, finish);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -51,8 +51,8 @@ function testAddProviders(manifests, next) {
|
||||
|
||||
function testRemoveProviders(manifests, next) {
|
||||
do_check_true(SocialService.enabled);
|
||||
yield SocialService.removeProvider(manifests[0].origin, next);
|
||||
yield SocialService.removeProvider(manifests[1].origin, next);
|
||||
yield SocialService.disableProvider(manifests[0].origin, next);
|
||||
yield SocialService.disableProvider(manifests[1].origin, next);
|
||||
do_check_false(SocialService.enabled);
|
||||
}
|
||||
|
||||
@ -106,7 +106,7 @@ function testAddRemoveProvider(manifests, next) {
|
||||
do_check_neq(providersAfter.indexOf(newProvider), -1);
|
||||
|
||||
// Now remove the provider
|
||||
yield SocialService.removeProvider(newProvider.origin, next);
|
||||
yield SocialService.disableProvider(newProvider.origin, next);
|
||||
providersAfter = yield SocialService.getProviderList(next);
|
||||
do_check_eq(providersAfter.length, originalProviders.length);
|
||||
do_check_eq(providersAfter.indexOf(newProvider), -1);
|
||||
|
@ -205,7 +205,7 @@ static void WriteSubmissionEvent(SubmissionResult result,
|
||||
|
||||
string localId = GetDumpLocalID();
|
||||
string fpath = gEventsPath + UI_DIR_SEPARATOR + localId + "-submission";
|
||||
ofstream* f = UIOpenWrite(fpath.c_str());
|
||||
ofstream* f = UIOpenWrite(fpath.c_str(), false, true);
|
||||
time_t tm;
|
||||
time(&tm);
|
||||
|
||||
|
@ -141,7 +141,9 @@ bool UIFileExists(const std::string& path);
|
||||
bool UIMoveFile(const std::string& oldfile, const std::string& newfile);
|
||||
bool UIDeleteFile(const std::string& oldfile);
|
||||
std::ifstream* UIOpenRead(const std::string& filename);
|
||||
std::ofstream* UIOpenWrite(const std::string& filename, bool append=false);
|
||||
std::ofstream* UIOpenWrite(const std::string& filename,
|
||||
bool append=false,
|
||||
bool binary=false);
|
||||
void UIPruneSavedDumps(const std::string& directory);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -439,9 +439,19 @@ std::ifstream* UIOpenRead(const string& filename)
|
||||
return new std::ifstream(filename.c_str(), std::ios::in);
|
||||
}
|
||||
|
||||
std::ofstream* UIOpenWrite(const string& filename, bool append) // append=false
|
||||
std::ofstream* UIOpenWrite(const string& filename,
|
||||
bool append, // append=false
|
||||
bool binary) // binary=false
|
||||
{
|
||||
return new std::ofstream(filename.c_str(),
|
||||
append ? std::ios::out | std::ios::app
|
||||
: std::ios::out);
|
||||
std::ios_base::openmode mode = std::ios::out;
|
||||
|
||||
if (append) {
|
||||
mode = mode | std::ios::app;
|
||||
}
|
||||
|
||||
if (binary) {
|
||||
mode = mode | std::ios::binary;
|
||||
}
|
||||
|
||||
return new std::ofstream(filename.c_str(), mode);
|
||||
}
|
||||
|
@ -887,9 +887,19 @@ std::ifstream* UIOpenRead(const string& filename)
|
||||
return new std::ifstream(filename.c_str(), std::ios::in);
|
||||
}
|
||||
|
||||
std::ofstream* UIOpenWrite(const string& filename, bool append) // append=false
|
||||
std::ofstream* UIOpenWrite(const string& filename,
|
||||
bool append, // append=false
|
||||
bool binary) // binary=false
|
||||
{
|
||||
return new std::ofstream(filename.c_str(),
|
||||
append ? std::ios::out | std::ios::app
|
||||
: std::ios::out);
|
||||
std::ios_base::openmode mode = std::ios::out;
|
||||
|
||||
if (append) {
|
||||
mode = mode | std::ios::app;
|
||||
}
|
||||
|
||||
if (binary) {
|
||||
mode = mode | std::ios::binary;
|
||||
}
|
||||
|
||||
return new std::ofstream(filename.c_str(), mode);
|
||||
}
|
||||
|
@ -1452,24 +1452,30 @@ ifstream* UIOpenRead(const string& filename)
|
||||
return file;
|
||||
}
|
||||
|
||||
ofstream* UIOpenWrite(const string& filename, bool append) // append=false
|
||||
ofstream* UIOpenWrite(const string& filename,
|
||||
bool append, // append=false
|
||||
bool binary) // binary=false
|
||||
{
|
||||
// adapted from breakpad's src/common/windows/http_upload.cc
|
||||
std::ios_base::openmode mode = ios::out;
|
||||
if (append) {
|
||||
mode = mode | ios::app;
|
||||
}
|
||||
if (binary) {
|
||||
mode = mode | ios::binary;
|
||||
}
|
||||
|
||||
// The "open" method on pre-MSVC8 ifstream implementations doesn't accept a
|
||||
// wchar_t* filename, so use _wfopen directly in that case. For VC8 and
|
||||
// later, _wfopen has been deprecated in favor of _wfopen_s, which does
|
||||
// not exist in earlier versions, so let the ifstream open the file itself.
|
||||
// For VC8 and later, _wfopen has been deprecated in favor of _wfopen_s,
|
||||
// which does not exist in earlier versions, so let the ifstream open the
|
||||
// file itself.
|
||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||
ofstream* file = new ofstream();
|
||||
file->open(UTF8ToWide(filename).c_str(), append ? ios::out | ios::app
|
||||
: ios::out);
|
||||
file->open(UTF8ToWide(filename).c_str(), mode);
|
||||
#elif defined(_MSC_VER)
|
||||
ofstream* file = new ofstream(_wfopen(UTF8ToWide(filename).c_str(),
|
||||
append ? L"a" : L"w"));
|
||||
#error "Compiling with your version of MSVC is no longer supported."
|
||||
#else // GCC
|
||||
ofstream* file = new ofstream(WideToMBCP(UTF8ToWide(filename), CP_ACP).c_str(),
|
||||
append ? ios::out | ios::app : ios::out);
|
||||
mode);
|
||||
#endif // _MSC_VER >= 1400
|
||||
|
||||
return file;
|
||||
|
@ -191,7 +191,11 @@ InlineSpellChecker.prototype = {
|
||||
if (curlang == sortedList[i].id) {
|
||||
item.setAttribute("checked", "true");
|
||||
} else {
|
||||
var callback = function(me, val) { return function(evt) { me.selectDictionary(val, me.menu.ownerDocument.defaultView); } };
|
||||
var callback = function(me, val) {
|
||||
return function(evt) {
|
||||
me.selectDictionary(val, menu.ownerDocument.defaultView);
|
||||
}
|
||||
};
|
||||
item.addEventListener("command", callback(this, i), true);
|
||||
}
|
||||
if (insertBefore)
|
||||
|
@ -128,6 +128,39 @@ functionality will not be enabled or you will be prompted for your
|
||||
Bugzilla credentials when they are needed.
|
||||
'''.lstrip()
|
||||
|
||||
BZPOST_MINIMUM_VERSION = StrictVersion('3.0')
|
||||
|
||||
BZPOST_INFO = '''
|
||||
The bzpost extension automatically records the URLs of pushed commits to
|
||||
referenced Bugzilla bugs after push.
|
||||
|
||||
Would you like to activate bzpost
|
||||
'''.strip()
|
||||
|
||||
FIREFOXTREE_MINIMUM_VERSION = StrictVersion('3.0')
|
||||
|
||||
FIREFOXTREE_INFO = '''
|
||||
The firefoxtree extension makes interacting with the multiple Firefox
|
||||
repositories easier:
|
||||
|
||||
* Aliases for common trees are pre-defined. e.g. `hg pull central`
|
||||
* Pulling from known Firefox trees will create "remote refs" appearing as
|
||||
tags. e.g. pulling from fx-team will produce a "fx-team" tag.
|
||||
* The `hg fxheads` command will list the heads of all pulled Firefox repos
|
||||
for easy reference.
|
||||
* `hg push` will limit itself to pushing a single head when pushing to
|
||||
Firefox repos.
|
||||
* A pre-push hook will prevent you from pushing multiple heads to known
|
||||
Firefox repos. This acts quicker than a server-side hook.
|
||||
|
||||
The firefoxtree extension is *strongly* recommended if you:
|
||||
|
||||
a) aggregate multiple Firefox repositories into a single local repo
|
||||
b) perform head/bookmark-based development (as opposed to mq)
|
||||
|
||||
Would you like to activate firefoxtree
|
||||
'''.strip()
|
||||
|
||||
class MercurialSetupWizard(object):
|
||||
"""Command-line wizard to help users configure Mercurial."""
|
||||
|
||||
@ -233,6 +266,12 @@ class MercurialSetupWizard(object):
|
||||
'projects',
|
||||
path=p)
|
||||
|
||||
if hg_version >= BZPOST_MINIMUM_VERSION:
|
||||
self.prompt_external_extension(c, 'bzpost', BZPOST_INFO)
|
||||
|
||||
if hg_version >= FIREFOXTREE_MINIMUM_VERSION:
|
||||
self.prompt_external_extension(c, 'firefoxtree', FIREFOXTREE_INFO)
|
||||
|
||||
if 'mq' in c.extensions:
|
||||
self.prompt_external_extension(c, 'mqext', MQEXT_INFO,
|
||||
os.path.join(self.ext_dir, 'mqext'))
|
||||
@ -261,7 +300,7 @@ class MercurialSetupWizard(object):
|
||||
print('Configured qnew to set patch author by default.')
|
||||
print('')
|
||||
|
||||
if 'reviewboard' in c.extensions:
|
||||
if 'reviewboard' in c.extensions or 'bzpost' in c.extensions:
|
||||
bzuser, bzpass = c.get_bugzilla_credentials()
|
||||
|
||||
if not bzuser or not bzpass:
|
||||
@ -346,7 +385,11 @@ class MercurialSetupWizard(object):
|
||||
# in a directory with the same name as the extension and thus also
|
||||
# flagging the version-control-tools repo as needing an update.
|
||||
if name not in c.extensions:
|
||||
print(name)
|
||||
print('=' * len(name))
|
||||
print('')
|
||||
if not self._prompt_yn(prompt_text):
|
||||
print('')
|
||||
return
|
||||
print('Activated %s extension.\n' % name)
|
||||
if not path:
|
||||
|
Loading…
Reference in New Issue
Block a user