From 6653745c484fa501ed34655c8012e855fcfa8ca0 Mon Sep 17 00:00:00 2001 From: "beng%bengoodger.com" Date: Sat, 6 May 2006 02:37:51 +0000 Subject: [PATCH] 335443 - support autodetection of search engines patch by Pam Greene r=brettw@gmail.com sr=ben@mozilla.org git-svn-id: svn://10.0.0.236/trunk@196086 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/browser/base/content/browser.js | 93 ++++++++++++++++- .../components/feeds/content/options.js | 16 +-- .../components/search/content/search.xml | 96 ++++++++++++++++-- .../components/search/nsSearchService.js | 41 +++++--- .../en-US/chrome/browser/search.properties | 4 + .../pinstripe/browser/Search-add-engines.png | Bin 0 -> 1462 bytes .../browser/themes/pinstripe/browser/jar.mn | 1 + .../themes/pinstripe/browser/searchbar.css | 6 +- .../winstripe/browser/Search-add-engines.png | Bin 0 -> 1462 bytes .../browser/themes/winstripe/browser/jar.mn | 1 + .../themes/winstripe/browser/searchbar.css | 7 +- mozilla/toolkit/components/Makefile.in | 1 + .../toolkit/content/widgets/tabbrowser.xml | 12 +++ 13 files changed, 242 insertions(+), 36 deletions(-) create mode 100755 mozilla/browser/themes/pinstripe/browser/Search-add-engines.png create mode 100755 mozilla/browser/themes/winstripe/browser/Search-add-engines.png diff --git a/mozilla/browser/base/content/browser.js b/mozilla/browser/base/content/browser.js index f39f188231d..86b4d3cbe04 100644 --- a/mozilla/browser/base/content/browser.js +++ b/mozilla/browser/base/content/browser.js @@ -37,6 +37,7 @@ # Tom Germeau # Jesse Ruderman # Joe Hughes +# Pamela Greene # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or @@ -914,6 +915,9 @@ function prepareForStartup() // Initialize the feedhandler FeedHandler.init(); + + // Initialize the searchbar + BrowserSearch.init(); } function delayedStartup() @@ -2886,6 +2890,85 @@ var DownloadsButtonDNDObserver = { } const BrowserSearch = { + + /** + * Initialize the BrowserSearch + */ + init: function() { + gBrowser.addEventListener("DOMLinkAdded", + function (event) { BrowserSearch.onLinkAdded(event); }, + false); + }, + + /** + * A new tag has been discovered - check to see if it advertises + * a OpenSearch engine. + */ + onLinkAdded: function(event) { + // XXX this event listener can/should probably be combined with the onLinkAdded + // listener in tabbrowser.xml. See comments in FeedHandler.onLinkAdded(). + const target = event.target; + var erel = target.rel; + var etype = target.type; + var etitle = target.title; + var ehref = target.href; + const searchRelRegex = /(^|\s)search($|\s)/i; + const searchHrefRegexHttp = /^http:\/\//i; + const searchHrefRegexHttps = /^https:\/\//i; + + if (!etype) + return; + + if (etype == "application/opensearchdescription+xml" && + searchRelRegex.test(erel) && + (searchHrefRegexHttp.test(ehref) || searchHrefRegexHttps.test(ehref))) + { + const targetDoc = target.ownerDocument; + // Set the attribute of the (first) search button. + var searchButton = document.getAnonymousElementByAttribute(this.getSearchBar(), + "anonid", "searchbar-dropmarker"); + if (searchButton) { + var browser = gBrowser.getBrowserForDocument(targetDoc); + // Append the URI and an appropriate title to the browser data. + var engines = []; + if (browser.engines) + engines = browser.engines; + + var iconURL = null; + if (gBrowser.shouldLoadFavIcon(browser.currentURI)) + iconURL = browser.currentURI.prePath + "/favicon.ico"; + var usableTitle = target.title || browser.contentTitle || target.href; + engines.push({ uri: target.href, + title: usableTitle, + icon: iconURL }); + browser.engines = engines; + + if (browser == gBrowser || browser == gBrowser.mCurrentBrowser) + this.updateSearchButton(); + } + } + }, + + /** + * Update the browser UI to show whether or not additional engines are + * available when a page is loaded or the user switches tabs to a page that + * has search engines. + */ + updateSearchButton: function() { + var searchButton = document.getAnonymousElementByAttribute(this.getSearchBar(), + "anonid", "searchbar-dropmarker"); + if (!searchButton) + return; + var engines = gBrowser.mCurrentBrowser.engines; + if (!engines || engines.length == 0) { + if (searchButton.hasAttribute("addengines")) + searchButton.removeAttribute("addengines"); + } + else { + searchButton.setAttribute("addengines", "true"); + } + }, + /** * Gives focus to the search bar, if it is present on the toolbar, or loads * the default engine's search form otherwise. For Mac, opens a new window @@ -2951,7 +3034,7 @@ const BrowserSearch = { } else loadURI(submission.uri.spec, null, submission.postData, false); }, - + /** * Returns the search bar element if it is present in the toolbar and not * hidden, null otherwise. @@ -3702,6 +3785,7 @@ nsBrowserStatusHandler.prototype = asyncUpdateUI : function () { FeedHandler.updateFeeds(); + BrowserSearch.updateSearchButton(); #ifdef ALTSS_ICON updatePageStyles(); #endif @@ -3793,6 +3877,9 @@ nsBrowserStatusHandler.prototype = // clear out feed data gBrowser.mCurrentBrowser.feeds = null; + // clear out search-engine data + gBrowser.mCurrentBrowser.engines = null; + const nsIChannel = Components.interfaces.nsIChannel; var urlStr = aRequest.QueryInterface(nsIChannel).URI.spec; var observerService = Components.classes["@mozilla.org/observer-service;1"] @@ -6310,9 +6397,7 @@ var FeedHandler = { const targetDoc = event.target.ownerDocument; // find which tab this is for, and set the attribute on the browser - // should there be a getTabForDocument method on tabbedbrowser? - var shellInfo = this._getContentShell(targetDoc); - var browserForLink = shellInfo.browser; + var browserForLink = gBrowser.getBrowserForDocument(targetDoc); if (!browserForLink) { // ??? this really shouldn't happen.. return; diff --git a/mozilla/browser/components/feeds/content/options.js b/mozilla/browser/components/feeds/content/options.js index 5a6db831c90..23b3f2a4ae1 100644 --- a/mozilla/browser/components/feeds/content/options.js +++ b/mozilla/browser/components/feeds/content/options.js @@ -65,14 +65,6 @@ var SubscriptionOptions = { catch (e) { } - var reader = document.getElementById("reader"); - try { - reader.value = prefs.getCharPref(PREF_SELECTED_HANDLER); - } - catch (e) { - reader.value = "bookmarks"; - } - var clientApp = document.getElementById("clientApp"); try { clientApp.file = @@ -118,6 +110,14 @@ var SubscriptionOptions = { catch (e) { webService.selectedIndex = 0; } + + var reader = document.getElementById("reader"); + try { + reader.value = prefs.getCharPref(PREF_SELECTED_HANDLER); + } + catch (e) { + reader.value = "bookmarks"; + } }, populateWebHandlers: function SO_populateWebHandlers(popup) { diff --git a/mozilla/browser/components/search/content/search.xml b/mozilla/browser/components/search/content/search.xml index 46c7b6fd65b..5e83c3fcf54 100644 --- a/mozilla/browser/components/search/content/search.xml +++ b/mozilla/browser/components/search/content/search.xml @@ -24,6 +24,7 @@ # Pierre Chanial (v2) # Gavin Sharp (v3) # Ben Goodger +# Pamela Greene # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or @@ -198,6 +199,67 @@ ]]> + + + = 0; i--) { + if (items[i].getAttribute("class").indexOf("addengine") != -1) + popup.removeChild(items[i]); + } + + var addengines = getBrowser().mCurrentBrowser.engines; + if (addengines && addengines.length > 0) { + const kXULNS = + "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + + // Find the (first) separator in the remaining menu, or the first item + // if no separators are present. + var insertLocation = popup.firstChild; + while (insertLocation.nextSibling && + insertLocation.localName != "menuseparator") { + insertLocation = insertLocation.nextSibling; + } + if (insertLocation.localName != "menuseparator") + insertLocation = popup.firstChild; + + var separator = document.createElementNS(kXULNS, "menuseparator"); + separator.setAttribute("class", "addengine-separator"); + popup.insertBefore(separator, insertLocation); + + // Insert the "add this engine" items. + for (var i = 0; i < addengines.length; i++) { + menuitem = document.createElement("menuitem"); + var engineInfo = addengines[i]; + var labelStr = + this._stringBundle.getFormattedString("cmd_addFoundEngine", + [engineInfo.title]); + menuitem = document.createElementNS(kXULNS, "menuitem"); + menuitem.setAttribute("class", "menuitem-iconic addengine-item"); + menuitem.setAttribute("label", labelStr); + menuitem.setAttribute("tooltiptext", engineInfo.uri); + menuitem.setAttribute("uri", engineInfo.uri); + if (engineInfo.icon) + menuitem.setAttribute("src", engineInfo.icon); + menuitem.setAttribute("title", engineInfo.title); + popup.insertBefore(menuitem, insertLocation); + } + } + ]]> + + + = 0; --i) { var menuitem = document.createElementNS(kXULNS, "menuitem"); var name = this._engines[i].name; @@ -259,7 +320,23 @@ + ]]> + + @@ -400,8 +480,8 @@ \n" + const BROWSER_SEARCH_PREF = "browser.search."; -// Unsupported search parameters. +// Unsupported search parameters, which will be replaced with blanks. // XXX We do use inputEncoding - should consider having it available. This -// would require doing multiple parameter substition, so just having +// would require doing multiple parameter substitution, so just having // searchTerms is sufficient for now. -const kIllegalWords = /(\{count\})|(\{startIndex\})|(\{startPage\})|(\{language\})|(\{outputEncoding\})|(\{inputEncoding\})/; +const kInvalidWords = /(\{count\})|(\{startIndex\})|(\{startPage\})|(\{language\})|(\{outputEncoding\})|(\{inputEncoding\})/; +// Supported search parameters. const kValidWords = /\{searchTerms\}/gi; const kUserDefined = "{searchTerms}"; @@ -581,12 +587,12 @@ function notifyAction(aEngine, aVerb) { * Simple object representing a name/value pair. * @throws NS_ERROR_NOT_IMPLEMENTED if the provided value includes unsupported * parameters. - * @see kIllegalWords. + * @see kInvalidWords. */ function QueryParameter(aName, aValue) { ENSURE_ARG(aName && aValue, "missing name or value for QueryParameter!"); - ENSURE(!kIllegalWords.test(aValue), + ENSURE(!kInvalidWords.test(aValue), "Illegal value while creating a QueryParameter", Cr.NS_ERROR_NOT_IMPLEMENTED); @@ -610,10 +616,10 @@ function QueryParameter(aName, aValue) { * * @see http://opensearch.a9.com/spec/1.1/querysyntax/#urltag * - * @throws NS_ERROR_NOT_IMPLEMENTED if aType is unsupported, or if aTemplate - * includes unsupported parameters. - * - * @see kIllegalWords. + * @throws NS_ERROR_NOT_IMPLEMENTED if aType is unsupported. If invalid + * (unsupported) parameters are included in aTemplate, they will be + * replaced with blanks in the final query, so no error needs to be + * returned here. */ function EngineURL(aType, aMethod, aTemplate) { ENSURE_ARG(aType && aMethod && aTemplate, @@ -628,9 +634,6 @@ function EngineURL(aType, aMethod, aTemplate) { ENSURE(type == "text/html", "EngineURLs must be of type text/html!", Cr.NS_ERROR_NOT_IMPLEMENTED); - ENSURE(!kIllegalWords.test(aTemplate), "Invalid URL parameter!", - Cr.NS_ERROR_NOT_IMPLEMENTED); - this.type = type; this.method = method; this.template = aTemplate; @@ -647,6 +650,8 @@ EngineURL.prototype = { * From an array of QueryParameter objects, generates a string in the * application/x-www-form-urlencoded format: * name=value&name=value&name=value... + * Any invalid or unimplemented query fields will be replqaced with empty + * strings. * @param aParams * An array of QueryParameter objects * @param aData @@ -654,6 +659,8 @@ EngineURL.prototype = { * |kValidWords| regexp * @returns A string of encoded param names and values in * application/x-www-form-urlencoded format. + * + * @see kInvalidWords */ function makeQueryString(aParams, aData) { var str = ""; @@ -665,7 +672,9 @@ EngineURL.prototype = { return str; } + // Replace known fields with given parameters and clear unknown fields. var url = this.template.replace(kValidWords, aData); + url = url.replace(kInvalidWords, ""); var postData = null; var dataString = makeQueryString(this.params, aData); if (this.method == "GET") { @@ -1010,7 +1019,9 @@ Engine.prototype = { this._parseAsMozSearch(); } else if (checkNameSpace(this._data, [kOpenSearchLocalName], - [kOpenSearchNS_11, kOpenSearchNS_10])) { + [kOpenSearchNS_11, kOpenSearchNS_10]) || + checkNameSpace(this._data, [kOpenSearchLocalName], + [kOpenSearchNS_11_alt, kOpenSearchNS_10_alt])) { LOG("_init: Initing OpenSearch plugin from " + this._location); @@ -1073,6 +1084,10 @@ Engine.prototype = { var method = aElement.getAttribute("method"); var template = aElement.getAttribute("template"); + // According to the spec, method is an optional attribute, defaulting to "get". + if (!method) + method = "get"; + var url = new EngineURL(type, method, template); for (var i = 0; i < aElement.childNodes.length; ++i) { diff --git a/mozilla/browser/locales/en-US/chrome/browser/search.properties b/mozilla/browser/locales/en-US/chrome/browser/search.properties index 89291bf11f0..cedb5ed2e4a 100755 --- a/mozilla/browser/locales/en-US/chrome/browser/search.properties +++ b/mozilla/browser/locales/en-US/chrome/browser/search.properties @@ -6,3 +6,7 @@ cmd_clearHistory_accesskey=C error_loading_engine_title=Download Error error_loading_engine_msg=%S could not download the search plugin from:\n%S\n\nPlease try again or contact the author. + +cmd_addFoundEngine=Add "%S" +cmd_addEngine=Add More Engines... +cmd_addEngine_accesskey=A diff --git a/mozilla/browser/themes/pinstripe/browser/Search-add-engines.png b/mozilla/browser/themes/pinstripe/browser/Search-add-engines.png new file mode 100755 index 0000000000000000000000000000000000000000..a2738f2c547d2fdfb7f4eb925b8f918cc02100ed GIT binary patch literal 1462 zcmV;n1xfmeP)m|G>Bh`S|^k?TeMnj8Er>4U8Atp(rMF$uV`h4D{z@V+J@m?C z9t^aCt*$X6;QFJ@wQryA)AJs$ch}7ISATr=+@5zSY<86e03M z5KxT0WX6kg@30*xtL{b?2&)@=1}Ru;AOYfAw-?<5LP$#4ASs*1`;8Dlnp>gad?Veo|k7mRIxGu z5K3tQo{!f?k@*lm$_8o@6C?Qe--_yxub4UKeq&Er0fn&!o`AjrHS(~`5l^x+ORu;>02RUGj!1IC?2%jnI8izE1e z8OV7)E4PCUtT$&w@FB)Xs1)*#`9##G_hoyE$~~LWeMLxVMTk7H%L-W585l zFj!Epwx=z(DQHAx-vea|#J915_m?fNmSqsDmI3oM226m3O9xOGd=A97v4M5z<_JE- zq-hM8f=yd2*P2^xv~`z4dpZ?5=2alRO&B=TQ!UFVRxKkT0Od1zu6{$XDL2m!C=jF^ zEPq6SF=c$?W(5sB%myHGQ8WW6pGh=%5Wnp#dQEDoqMieuf`%Su1C<6t1Ya1qGBrt; zCxWzNuN_cm{|SXo4=6CE&^1!f(8I#O-h+#x889OHo!kRhJzv$;+rMwzsQkHUt3um9 zR4|p?vWd^ilF)~j5R7$l4`B7YUU0XavxajNJ_kd=Et@zhUzCu4tW)%Wf6PM{f40-F z5KR&TSKYFS&*E7#Ppt3~Nh7yy1b zMgxev3k~n$sl;Pc8t`f|pwna^iFSA7V-or07!4ruE*kmWC8iRO(Z3CNH5t%pGr$o^ zLy8L!H80--nv0B30)3yC)eLe8VWsxv4>ih06e3hUP=M%r`5w?*WQ243UYctiC@Ff#VW<8Ckuob#+Y{J#JI0RR630QHioR2uDo QasU7T07*qoM6N<$f-HETH~;_u literal 0 HcmV?d00001 diff --git a/mozilla/browser/themes/pinstripe/browser/jar.mn b/mozilla/browser/themes/pinstripe/browser/jar.mn index f113c9c018d..9e33718c991 100644 --- a/mozilla/browser/themes/pinstripe/browser/jar.mn +++ b/mozilla/browser/themes/pinstripe/browser/jar.mn @@ -23,6 +23,7 @@ classic.jar: skin/classic/browser/search-bar-background.png skin/classic/browser/Search-bar.png skin/classic/browser/Search.png + skin/classic/browser/Search-add-engines.png skin/classic/browser/Secure.png skin/classic/browser/Security-broken.png skin/classic/browser/Secure-urlbar.png diff --git a/mozilla/browser/themes/pinstripe/browser/searchbar.css b/mozilla/browser/themes/pinstripe/browser/searchbar.css index 59a2dbc5c6b..ed8291630b6 100644 --- a/mozilla/browser/themes/pinstripe/browser/searchbar.css +++ b/mozilla/browser/themes/pinstripe/browser/searchbar.css @@ -33,6 +33,10 @@ padding: 0px; } +.search-go-button[addengines="true"] { + list-style-image: url("chrome://browser/skin/Search-add-engines.png"); +} + .search-go-button:hover { -moz-image-region: rect(0px 32px 16px 16px); } @@ -45,6 +49,6 @@ -moz-image-region: rect(0px, 48px, 16px, 32px); } -.searchbar-engine-menuitem[selected="true"] .menu-iconic-text { +.searchbar-engine-menuitem[selected="true"] > .menu-iconic-text { font-weight: bold; } diff --git a/mozilla/browser/themes/winstripe/browser/Search-add-engines.png b/mozilla/browser/themes/winstripe/browser/Search-add-engines.png new file mode 100755 index 0000000000000000000000000000000000000000..a2738f2c547d2fdfb7f4eb925b8f918cc02100ed GIT binary patch literal 1462 zcmV;n1xfmeP)m|G>Bh`S|^k?TeMnj8Er>4U8Atp(rMF$uV`h4D{z@V+J@m?C z9t^aCt*$X6;QFJ@wQryA)AJs$ch}7ISATr=+@5zSY<86e03M z5KxT0WX6kg@30*xtL{b?2&)@=1}Ru;AOYfAw-?<5LP$#4ASs*1`;8Dlnp>gad?Veo|k7mRIxGu z5K3tQo{!f?k@*lm$_8o@6C?Qe--_yxub4UKeq&Er0fn&!o`AjrHS(~`5l^x+ORu;>02RUGj!1IC?2%jnI8izE1e z8OV7)E4PCUtT$&w@FB)Xs1)*#`9##G_hoyE$~~LWeMLxVMTk7H%L-W585l zFj!Epwx=z(DQHAx-vea|#J915_m?fNmSqsDmI3oM226m3O9xOGd=A97v4M5z<_JE- zq-hM8f=yd2*P2^xv~`z4dpZ?5=2alRO&B=TQ!UFVRxKkT0Od1zu6{$XDL2m!C=jF^ zEPq6SF=c$?W(5sB%myHGQ8WW6pGh=%5Wnp#dQEDoqMieuf`%Su1C<6t1Ya1qGBrt; zCxWzNuN_cm{|SXo4=6CE&^1!f(8I#O-h+#x889OHo!kRhJzv$;+rMwzsQkHUt3um9 zR4|p?vWd^ilF)~j5R7$l4`B7YUU0XavxajNJ_kd=Et@zhUzCu4tW)%Wf6PM{f40-F z5KR&TSKYFS&*E7#Ppt3~Nh7yy1b zMgxev3k~n$sl;Pc8t`f|pwna^iFSA7V-or07!4ruE*kmWC8iRO(Z3CNH5t%pGr$o^ zLy8L!H80--nv0B30)3yC)eLe8VWsxv4>ih06e3hUP=M%r`5w?*WQ243UYctiC@Ff#VW<8Ckuob#+Y{J#JI0RR630QHioR2uDo QasU7T07*qoM6N<$f-HETH~;_u literal 0 HcmV?d00001 diff --git a/mozilla/browser/themes/winstripe/browser/jar.mn b/mozilla/browser/themes/winstripe/browser/jar.mn index 89defcf7260..9b157f2abb5 100644 --- a/mozilla/browser/themes/winstripe/browser/jar.mn +++ b/mozilla/browser/themes/winstripe/browser/jar.mn @@ -14,6 +14,7 @@ classic.jar: skin/classic/browser/search-arrow.gif skin/classic/browser/Search-bar.png skin/classic/browser/Search.png + skin/classic/browser/Search-add-engines.png skin/classic/browser/Secure.png skin/classic/browser/Security-broken.png skin/classic/browser/Throbber.gif diff --git a/mozilla/browser/themes/winstripe/browser/searchbar.css b/mozilla/browser/themes/winstripe/browser/searchbar.css index dc75b452377..2618b4fa0ae 100644 --- a/mozilla/browser/themes/winstripe/browser/searchbar.css +++ b/mozilla/browser/themes/winstripe/browser/searchbar.css @@ -52,6 +52,10 @@ padding-bottom: 0px; } +.search-go-button[addengines="true"] { + list-style-image: url("chrome://browser/skin/Search-add-engines.png"); +} + .search-go-button:hover { -moz-image-region: rect(0px 32px 16px 16px); } @@ -64,7 +68,6 @@ -moz-image-region: rect(0px, 48px, 16px, 32px); } - -.searchbar-engine-menuitem[selected="true"] .menu-iconic-text { +.searchbar-engine-menuitem[selected="true"] > .menu-iconic-text { font-weight: bold; } diff --git a/mozilla/toolkit/components/Makefile.in b/mozilla/toolkit/components/Makefile.in index e97b895a49e..2ebffd43092 100644 --- a/mozilla/toolkit/components/Makefile.in +++ b/mozilla/toolkit/components/Makefile.in @@ -60,6 +60,7 @@ DIRS += \ ifndef MOZ_SUITE # XXX Suite doesn't want these just yet DIRS += \ + feeds \ typeaheadfind \ viewconfig \ $(NULL) diff --git a/mozilla/toolkit/content/widgets/tabbrowser.xml b/mozilla/toolkit/content/widgets/tabbrowser.xml index b477e2202b4..d7ed6c23899 100644 --- a/mozilla/toolkit/content/widgets/tabbrowser.xml +++ b/mozilla/toolkit/content/widgets/tabbrowser.xml @@ -214,6 +214,18 @@ + + + + + + +