Bug 1042199 - Show a search box on error pages. r=margaret

This commit is contained in:
Wes Johnston 2014-09-16 16:34:52 -07:00
parent 7e8040ba9f
commit 0dbf84857e
8 changed files with 119 additions and 33 deletions

View File

@ -1813,11 +1813,11 @@ public class BrowserApp extends GeckoApp
final Tab tab = Tabs.getInstance().getSelectedTab(); final Tab tab = Tabs.getInstance().getSelectedTab();
if (tab != null) { if (tab != null) {
final String userSearch = tab.getUserSearch(); final String userRequested = tab.getUserRequested();
// Check to see if there's a user-entered search term, // Check to see if there's a user-entered search term,
// which we save whenever the user performs a search. // which we save whenever the user performs a search.
url = (TextUtils.isEmpty(userSearch) ? tab.getURL() : userSearch); url = (TextUtils.isEmpty(userRequested) ? tab.getURL() : userRequested);
} }
enterEditingMode(url); enterEditingMode(url);

View File

@ -38,7 +38,7 @@ public class Tab {
private long mLastUsed; private long mLastUsed;
private String mUrl; private String mUrl;
private String mBaseDomain; private String mBaseDomain;
private String mUserSearch; private String mUserRequested; // The original url requested. May be typed by the user or sent by an extneral app for example.
private String mTitle; private String mTitle;
private Bitmap mFavicon; private Bitmap mFavicon;
private String mFaviconUrl; private String mFaviconUrl;
@ -97,7 +97,7 @@ public class Tab {
mId = id; mId = id;
mUrl = url; mUrl = url;
mBaseDomain = ""; mBaseDomain = "";
mUserSearch = ""; mUserRequested = "";
mExternal = external; mExternal = external;
mParentId = parentId; mParentId = parentId;
mTitle = title == null ? "" : title; mTitle = title == null ? "" : title;
@ -147,9 +147,9 @@ public class Tab {
return mUrl; return mUrl;
} }
// mUserSearch should never be null, but it may be an empty string // mUserRequested should never be null, but it may be an empty string
public synchronized String getUserSearch() { public synchronized String getUserRequested() {
return mUserSearch; return mUserRequested;
} }
// mTitle should never be null, but it may be an empty string // mTitle should never be null, but it may be an empty string
@ -268,8 +268,8 @@ public class Tab {
} }
} }
private synchronized void updateUserSearch(String userSearch) { public synchronized void updateUserRequested(String userRequested) {
mUserSearch = userSearch; mUserRequested = userRequested;
} }
public void setErrorType(String type) { public void setErrorType(String type) {
@ -654,7 +654,7 @@ public class Tab {
} }
setContentType(message.getString("contentType")); setContentType(message.getString("contentType"));
updateUserSearch(message.getString("userSearch")); updateUserRequested(message.getString("userRequested"));
mBaseDomain = message.optString("baseDomain"); mBaseDomain = message.optString("baseDomain");
setHasFeeds(false); setHasFeeds(false);

View File

@ -488,6 +488,7 @@ public class Tabs implements GeckoEventListener {
notifyListeners(tab, Tabs.TabEvents.LOAD_ERROR); notifyListeners(tab, Tabs.TabEvents.LOAD_ERROR);
} else if (event.equals("Content:PageShow")) { } else if (event.equals("Content:PageShow")) {
notifyListeners(tab, TabEvents.PAGE_SHOW); notifyListeners(tab, TabEvents.PAGE_SHOW);
tab.updateUserRequested(message.getString("userRequested"));
} else if (event.equals("DOMContentLoaded")) { } else if (event.equals("DOMContentLoaded")) {
tab.handleContentLoaded(); tab.handleContentLoaded();
String backgroundColor = message.getString("bgColor"); String backgroundColor = message.getString("bgColor");

View File

@ -961,7 +961,8 @@ var BrowserApp = {
let tab = this.getTabForBrowser(aBrowser); let tab = this.getTabForBrowser(aBrowser);
if (tab) { if (tab) {
if ("userSearch" in aParams) tab.userSearch = aParams.userSearch; if ("userRequested" in aParams) tab.userRequested = aParams.userRequested;
tab.isSearch = ("isSearch" in aParams) ? aParams.isSearch : false;
} }
try { try {
@ -1585,13 +1586,15 @@ var BrowserApp = {
desktopMode: (data.desktopMode === true) desktopMode: (data.desktopMode === true)
}; };
params.userRequested = url;
if (data.engine) { if (data.engine) {
let engine = Services.search.getEngineByName(data.engine); let engine = Services.search.getEngineByName(data.engine);
if (engine) { if (engine) {
params.userSearch = url;
let submission = engine.getSubmission(url); let submission = engine.getSubmission(url);
url = submission.uri.spec; url = submission.uri.spec;
params.postData = submission.postData; params.postData = submission.postData;
params.isSearch = true;
} }
} }
@ -1623,7 +1626,7 @@ var BrowserApp = {
// This event refers to a search via the URL bar, not a bookmarks // This event refers to a search via the URL bar, not a bookmarks
// keyword search. Note that this code assumes that the user can only // keyword search. Note that this code assumes that the user can only
// perform a keyword search on the selected tab. // perform a keyword search on the selected tab.
this.selectedTab.userSearch = aData; this.isSearch = true;
// Don't store queries in private browsing mode. // Don't store queries in private browsing mode.
let isPrivate = PrivateBrowsingUtils.isWindowPrivate(this.selectedTab.browser.contentWindow); let isPrivate = PrivateBrowsingUtils.isWindowPrivate(this.selectedTab.browser.contentWindow);
@ -3265,7 +3268,8 @@ Tab.prototype = {
let charset = "charset" in aParams ? aParams.charset : null; let charset = "charset" in aParams ? aParams.charset : null;
// The search term the user entered to load the current URL // The search term the user entered to load the current URL
this.userSearch = "userSearch" in aParams ? aParams.userSearch : ""; this.userRequested = "userRequested" in aParams ? aParams.userRequested : "";
this.isSearch = "isSearch" in aParams ? aParams.isSearch : false;
try { try {
this.browser.loadURIWithFlags(aURL, flags, referrerURI, charset, postData); this.browser.loadURIWithFlags(aURL, flags, referrerURI, charset, postData);
@ -3794,16 +3798,6 @@ Tab.prototype = {
else if (docURI.startsWith("about:neterror")) else if (docURI.startsWith("about:neterror"))
errorType = "neterror"; errorType = "neterror";
Messaging.sendRequest({
type: "DOMContentLoaded",
tabID: this.id,
bgColor: backgroundColor,
errorType: errorType,
metadata: this.metatags
});
this.metatags = null;
// Attach a listener to watch for "click" events bubbling up from error // Attach a listener to watch for "click" events bubbling up from error
// pages and other similar page. This lets us fix bugs like 401575 which // pages and other similar page. This lets us fix bugs like 401575 which
// require error page UI to do privileged things, without letting error // require error page UI to do privileged things, without letting error
@ -3812,6 +3806,17 @@ Tab.prototype = {
NetErrorHelper.attachToBrowser(this.browser); NetErrorHelper.attachToBrowser(this.browser);
} }
Messaging.sendRequest({
type: "DOMContentLoaded",
tabID: this.id,
bgColor: backgroundColor,
errorType: errorType,
metadata: this.metatags,
});
// Reset isSearch so that the userRequested term will be erased on next page load
this.metatags = null;
if (docURI.startsWith("about:certerror") || docURI.startsWith("about:blocked")) { if (docURI.startsWith("about:certerror") || docURI.startsWith("about:blocked")) {
this.browser.addEventListener("click", ErrorPageEventHandler, true); this.browser.addEventListener("click", ErrorPageEventHandler, true);
let listener = function() { let listener = function() {
@ -4081,11 +4086,21 @@ Tab.prototype = {
if (aEvent.originalTarget.defaultView != this.browser.contentWindow) if (aEvent.originalTarget.defaultView != this.browser.contentWindow)
return; return;
let target = aEvent.originalTarget;
let docURI = target.documentURI;
if (!docURI.startsWith("about:neterror") && !this.isSearch) {
// If this wasn't an error page and the user isn't search, don't retain the typed entry
this.userRequested = "";
}
Messaging.sendRequest({ Messaging.sendRequest({
type: "Content:PageShow", type: "Content:PageShow",
tabID: this.id tabID: this.id,
userRequested: this.userRequested
}); });
this.isSearch = false;
if (!aEvent.persisted && Services.prefs.getBoolPref("browser.ui.linkify.phone")) { if (!aEvent.persisted && Services.prefs.getBoolPref("browser.ui.linkify.phone")) {
if (!this._linkifier) if (!this._linkifier)
this._linkifier = new Linkifier(); this._linkifier = new Linkifier();
@ -4268,7 +4283,7 @@ Tab.prototype = {
type: "Content:LocationChange", type: "Content:LocationChange",
tabID: this.id, tabID: this.id,
uri: truncate(fixedURI.spec, MAX_URI_LENGTH), uri: truncate(fixedURI.spec, MAX_URI_LENGTH),
userSearch: this.userSearch || "", userRequested: this.userRequested || "",
baseDomain: baseDomain, baseDomain: baseDomain,
contentType: (contentType ? contentType : ""), contentType: (contentType ? contentType : ""),
sameDocument: sameDocument sameDocument: sameDocument
@ -4276,9 +4291,6 @@ Tab.prototype = {
Messaging.sendRequest(message); Messaging.sendRequest(message);
// The search term is only valid for this location change event, so reset it here.
this.userSearch = "";
if (!sameDocument) { if (!sameDocument) {
// XXX This code assumes that this is the earliest hook we have at which // XXX This code assumes that this is the earliest hook we have at which
// browser.contentDocument is changed to the new document we're loading // browser.contentDocument is changed to the new document we're loading

View File

@ -299,9 +299,9 @@
</div> </div>
<div id="errorDescriptionsContainer"> <div id="errorDescriptionsContainer">
<div id="ed_generic">&generic.longDesc;</div> <div id="ed_generic">&generic.longDesc;</div>
<div id="ed_dnsNotFound">&dnsNotFound.longDesc3;</div> <div id="ed_dnsNotFound">&dnsNotFound.longDesc4;</div>
<div id="ed_fileNotFound">&fileNotFound.longDesc;</div> <div id="ed_fileNotFound">&fileNotFound.longDesc;</div>
<div id="ed_malformedURI">&malformedURI.longDesc;</div> <div id="ed_malformedURI">&malformedURI.longDesc2;</div>
<div id="ed_unknownProtocolFound">&unknownProtocolFound.longDesc;</div> <div id="ed_unknownProtocolFound">&unknownProtocolFound.longDesc;</div>
<div id="ed_connectionFailure">&connectionFailure.longDesc2;</div> <div id="ed_connectionFailure">&connectionFailure.longDesc2;</div>
<div id="ed_netTimeout">&netTimeout.longDesc2;</div> <div id="ed_netTimeout">&netTimeout.longDesc2;</div>

View File

@ -62,6 +62,36 @@ NetErrorHelper.prototype = {
}, },
} }
handlers.searchbutton = {
onPageShown: function(browser) {
let search = browser.contentDocument.querySelector("#searchbox");
if (!search) {
return;
}
let browserWin = Services.wm.getMostRecentWindow("navigator:browser");
let tab = browserWin.BrowserApp.getTabForBrowser(browser);
// If there is no stored userRequested, just hide the searchbox
if (!tab.userRequested) {
search.style.display = "none";
} else {
let text = browser.contentDocument.querySelector("#searchtext");
text.value = tab.userRequested;
}
},
handleClick: function(event) {
let engine = Services.search.defaultEngine;
let value = event.target.previousElementSibling.value;
let uri = engine.getSubmission(value).uri;
let browserWin = Services.wm.getMostRecentWindow("navigator:browser");
// Reset the user search to whatever the new search term was
browserWin.BrowserApp.loadURI(uri.spec, undefined, { isSearch: true, userRequested: value });
}
};
handlers.wifi = { handlers.wifi = {
// This registers itself with the nsIObserverService as a weak ref, // This registers itself with the nsIObserverService as a weak ref,
// so we have to implement GetWeakReference as well. // so we have to implement GetWeakReference as well.

View File

@ -199,3 +199,28 @@ div[collapsed="true"] > .expander + * {
} }
} }
} }
#searchbox {
padding: 0;
display: flex;
margin: var(--moz-vertical-spacing) -1em;
}
#searchbox > input {
flex: 3;
padding: 0em 3em 0em 1em;
width: 100%;
border: none;
font-family: sans-serif;
background-image: none;
background-color: white;
border-radius-top-right: none;
border-radius-bottom-right: none;
}
#searchbox > button {
flex: 1;
margin: 0;
width: auto;
}

View File

@ -17,11 +17,17 @@
<!ENTITY deniedPortAccess.longDesc ""> <!ENTITY deniedPortAccess.longDesc "">
<!ENTITY dnsNotFound.title "Server not found"> <!ENTITY dnsNotFound.title "Server not found">
<!ENTITY dnsNotFound.longDesc3 " <!-- LOCALIZATION NOTE (dnsNotFound.longDesc4) This string contains markup including widgets for searching
or enabling wifi connections. The text inside tags should be localized. Do not change the ids. -->
<!ENTITY dnsNotFound.longDesc4 "
<ul> <ul>
<li>Check the address for typing errors such as <li>Check the address for typing errors such as
<strong>ww</strong>.example.com instead of <strong>ww</strong>.example.com instead of
<strong>www</strong>.example.com</li> <strong>www</strong>.example.com</li>
<div id='searchbox'>
<input id='searchtext' type='search'></input>
<button id='searchbutton'>Search</button>
</div>
<li>If you are unable to load any pages, check your device's data or Wi-Fi connection. <li>If you are unable to load any pages, check your device's data or Wi-Fi connection.
<button id='wifi'>Enable Wi-Fi</button> <button id='wifi'>Enable Wi-Fi</button>
</li> </li>
@ -43,10 +49,16 @@
"> ">
<!ENTITY malformedURI.title "The address isn't valid"> <!ENTITY malformedURI.title "The address isn't valid">
<!ENTITY malformedURI.longDesc " <!-- LOCALIZATION NOTE (malformedURI.longDesc2) This string contains markup including widgets for searching
or enabling wifi connections. The text inside the tags should be localized. Do not touch the ids. -->
<!ENTITY malformedURI.longDesc2 "
<ul> <ul>
<li>Web addresses are usually written like <li>Web addresses are usually written like
<strong>http://www.example.com/</strong></li> <strong>http://www.example.com/</strong></li>
<div id='searchbox'>
<input id='searchtext' type='search'></input>
<button id='searchbutton'>Search</button>
</div>
<li>Make sure that you're using forward slashes (i.e. <li>Make sure that you're using forward slashes (i.e.
<strong>/</strong>).</li> <strong>/</strong>).</li>
</ul> </ul>
@ -59,6 +71,8 @@
<!ENTITY notCached.longDesc "<p>The requested document is not available in &brandShortName;'s cache.</p><ul><li>As a security precaution, &brandShortName; does not automatically re-request sensitive documents.</li><li>Click Try Again to re-request the document from the website.</li></ul>"> <!ENTITY notCached.longDesc "<p>The requested document is not available in &brandShortName;'s cache.</p><ul><li>As a security precaution, &brandShortName; does not automatically re-request sensitive documents.</li><li>Click Try Again to re-request the document from the website.</li></ul>">
<!ENTITY netOffline.title "Offline mode"> <!ENTITY netOffline.title "Offline mode">
<!-- LOCALIZATION NOTE (netOffline.longDesc3) This string contains markup including widgets enabling wifi connections.
The text inside the tags should be localized. Do not touch the ids. -->
<!ENTITY netOffline.longDesc3 " <!ENTITY netOffline.longDesc3 "
<ul> <ul>
<li>Try again. &brandShortName; will attempt to open a connection and reload the page. <li>Try again. &brandShortName; will attempt to open a connection and reload the page.
@ -104,6 +118,8 @@
"> ">
<!ENTITY proxyResolveFailure.title "Unable to find the proxy server"> <!ENTITY proxyResolveFailure.title "Unable to find the proxy server">
<!-- LOCALIZATION NOTE (proxyResolveFailure.longDesc3) This string contains markup including widgets for enabling wifi connections.
The text inside the tags should be localized. Do not touch the ids. -->
<!ENTITY proxyResolveFailure.longDesc3 " <!ENTITY proxyResolveFailure.longDesc3 "
<ul> <ul>
<li>Check the proxy settings to make sure that they are correct.</li> <li>Check the proxy settings to make sure that they are correct.</li>
@ -148,6 +164,8 @@ be temporary, and you can try again later.</li>
</ul> </ul>
"> ">
<!-- LOCALIZATION NOTE (sharedLongDesc3) This string contains markup including widgets for enabling wifi connections.
The text inside the tags should be localized. Do not touch the ids. -->
<!ENTITY sharedLongDesc3 " <!ENTITY sharedLongDesc3 "
<ul> <ul>
<li>The site could be temporarily unavailable or too busy. Try again in a few moments.</li> <li>The site could be temporarily unavailable or too busy. Try again in a few moments.</li>