This commit is contained in:
Robert Sayre 2010-03-26 15:56:20 -07:00
Родитель 66f3f0f7a3 14621ec75f
Коммит 60fc2a5c5e
47 изменённых файлов: 1248 добавлений и 107 удалений

Просмотреть файл

@ -240,6 +240,7 @@ pref("browser.urlbar.delay", 50);
pref("browser.urlbar.restrict.history", "^");
pref("browser.urlbar.restrict.bookmark", "*");
pref("browser.urlbar.restrict.tag", "+");
pref("browser.urlbar.restrict.openpage", "%");
pref("browser.urlbar.restrict.typed", "~");
pref("browser.urlbar.match.title", "#");
pref("browser.urlbar.match.url", "@");
@ -247,7 +248,8 @@ pref("browser.urlbar.match.url", "@");
// The default behavior for the urlbar can be configured to use any combination
// of the restrict or match filters with each additional filter restricting
// more (intersection). Add the following values to set the behavior as the
// default: 1: history, 2: bookmark, 4: tag, 8: title, 16: url, 32: typed
// default: 1: history, 2: bookmark, 4: tag, 8: title, 16: url, 32: typed,
// 64: javascript, 128: tabs
// E.g., 0 = show all results (no filtering), 1 = only visited pages in history,
// 2 = only bookmarks, 3 = visited bookmarks, 1+16 = history matching in the url
pref("browser.urlbar.default.behavior", 0);

Просмотреть файл

@ -51,6 +51,26 @@ toolbar[mode="icons"] > #reload-button[displaystop] {
-moz-binding: url(chrome://browser/content/urlbarBindings.xml#urlbar);
}
/* Some child nodes want to be ordered based on the locale's direction, while
everything else should be ltr. */
#urlbar:-moz-locale-dir(rtl) > .autocomplete-textbox-container > .textbox-input-box {
direction: rtl;
}
#urlbar html|*.autocomplete-textbox {
direction: ltr;
}
/* For results that are actions, their description text is shown instead of
the URL - this needs to follow the locale's direction, unlike URLs. */
richlistitem[type="action"]:-moz-locale-dir(rtl) > .ac-url-box {
direction: rtl;
}
#urlbar:not([actiontype]) > #urlbar-display {
display: none;
}
#wrapper-urlbar-container > #urlbar-container > #urlbar {
-moz-user-input: disabled;
cursor: -moz-grab;

Просмотреть файл

@ -3805,7 +3805,6 @@ var XULBrowserWindow = {
overLink: "",
startTime: 0,
statusText: "",
lastURI: null,
isBusy: false,
_progressCollapseTimer: 0,
@ -3869,7 +3868,6 @@ var XULBrowserWindow = {
delete this.statusTextField;
delete this.securityButton;
delete this.statusText;
delete this.lastURI;
},
setJSStatus: function (status) {
@ -4084,7 +4082,6 @@ var XULBrowserWindow = {
nBox.removeTransientNotifications();
}
}
selectedBrowser.lastURI = aLocationURI;
// Disable menu entries for images, enable otherwise
if (content.document && mimeTypeIsTextBased(content.document.contentType))
@ -7589,3 +7586,42 @@ var LightWeightThemeWebInstaller = {
node.baseURI);
}
}
function switchToTabHavingURI(aURI) {
function switchIfURIInWindow(aWindow) {
if (!("gBrowser" in aWindow))
return false;
let browsers = aWindow.gBrowser.browsers;
for (let i = 0; i < browsers.length; i++) {
let browser = browsers[i];
if (browser.currentURI.equals(aURI)) {
gURLBar.handleRevert();
aWindow.focus();
aWindow.gBrowser.tabContainer.selectedIndex = i;
return true;
}
}
return false;
}
// This can be passed either nsIURI or a string.
if (!(aURI instanceof Ci.nsIURI))
aURI = makeURI(aURI);
// Prioritise this window.
if (switchIfURIInWindow(window))
return true;
let winEnum = Services.wm.getEnumerator("navigator:browser");
while (winEnum.hasMoreElements()) {
let browserWin = winEnum.getNext();
// Skip closed (but not yet destroyed) windows,
// and the current window (which was checked earlier).
if (browserWin.closed || browserWin == window)
continue;
if (switchIfURIInWindow(browserWin))
return true;
}
// No opened tab has that url.
return false;
}

Просмотреть файл

@ -404,6 +404,7 @@
noneplaceholder="&urlbar.none.emptyText;"
type="autocomplete"
autocompletesearch="history"
autocompletesearchparam="enable-actions"
autocompletepopup="PopupAutoCompleteRichResult"
completeselectedindex="true"
tabscrolling="true"
@ -442,6 +443,7 @@
</hbox>
</hbox>
</box>
<label id="urlbar-display" value="&urlbar.switchToTab.label;"/>
<hbox id="urlbar-icons">
<button type="menu"
style="-moz-user-focus: none"

Просмотреть файл

@ -96,6 +96,10 @@
Components.classes["@mozilla.org/browser/favicon-service;1"]
.getService(Components.interfaces.nsIFaviconService);
</field>
<field name="mBrowserHistory" readonly="true">
Components.classes["@mozilla.org/browser/nav-history-service;1"]
.getService(Components.interfaces.nsIBrowserHistory);
</field>
<field name="mTabBox" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "tabbox");
</field>
@ -452,15 +456,30 @@
// changing location, clear out the missing plugins list
this.mBrowser.missingPlugins = null;
if (this.mBlank)
return;
var browserHistory = this.mTabBrowser.mBrowserHistory;
if ("lastURI" in this.mBrowser && this.mBrowser.lastURI)
browserHistory.unregisterOpenPage(this.mBrowser.lastURI);
browserHistory.registerOpenPage(aLocation);
if (this.mTabBrowser.mCurrentTab == this.mTab) {
for (let i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
let p = this.mTabBrowser.mProgressListeners[i];
if (!this.mBlank) {
if (this.mTabBrowser.mCurrentTab == this.mTab) {
for (let i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
let p = this.mTabBrowser.mProgressListeners[i];
if (p)
try {
p.onLocationChange(aWebProgress, aRequest, aLocation);
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
}
for (let i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) {
let p = this.mTabBrowser.mTabsProgressListeners[i];
if (p)
try {
p.onLocationChange(aWebProgress, aRequest, aLocation);
p.onLocationChange(this.mBrowser, aWebProgress, aRequest, aLocation);
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
@ -468,16 +487,8 @@
}
}
for (let i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) {
let p = this.mTabBrowser.mTabsProgressListeners[i];
if (p)
try {
p.onLocationChange(this.mBrowser, aWebProgress, aRequest, aLocation);
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
this.mBrowser.lastURI = aLocation;
},
onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
@ -1419,6 +1430,10 @@
filter.removeProgressListener(this.mTabListeners[aTab._tPos]);
this.mTabListeners[aTab._tPos].destroy();
let closedBrowser = this.getBrowserForTab(aTab);
if (closedBrowser.currentURI)
this.mBrowserHistory.unregisterOpenPage(closedBrowser.currentURI);
// We are no longer the primary content area.
browser.setAttribute("type", "content-targetable");
@ -2260,7 +2275,9 @@
<destructor>
<![CDATA[
for (var i = 0; i < this.mTabListeners.length; ++i) {
this.getBrowserAtIndex(i).webProgress.removeProgressListener(this.mTabFilters[i]);
let browser = this.getBrowserAtIndex(i);
this.mBrowserHistory.unregisterOpenPage(browser.currentURI);
browser.webProgress.removeProgressListener(this.mTabFilters[i]);
this.mTabFilters[i].removeProgressListener(this.mTabListeners[i]);
this.mTabFilters[i] = null;
this.mTabListeners[i].destroy();

Просмотреть файл

@ -150,6 +150,7 @@ _BROWSER_FILES = \
alltabslistener.html \
zoom_test.html \
dummy_page.html \
browser_tabMatchesInAwesomebar.js \
$(NULL)
ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))

Просмотреть файл

@ -0,0 +1,231 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim:set ts=2 sw=2 sts=2 et:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Places Test Code.
*
* The Initial Developer of the Original Code is the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Blair McBride <bmcbride@mozilla.com> (Original Author)
*
* 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
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
const TEST_URL_BASES = [
"http://example.org/browser/browser/base/content/test/dummy_page.html#tabmatch",
"http://example.org/browser/browser/base/content/test/moz.png#tabmatch"
];
var gPrivateBrowsing = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
var gTabWaitCount = 0;
var gTabCounter = 0;
var gTestSteps = [
function() {
info("Running step 1");
for (let i = 0; i < 10; i++) {
let tab = gBrowser.addTab();
loadTab(tab, TEST_URL_BASES[0] + (++gTabCounter));
}
},
function() {
info("Running step 2");
gBrowser.selectTabAtIndex(1);
gBrowser.removeCurrentTab();
gBrowser.selectTabAtIndex(1);
gBrowser.removeCurrentTab();
for (let i = 1; i < gBrowser.tabs.length; i++)
loadTab(gBrowser.tabs[i], TEST_URL_BASES[1] + (++gTabCounter));
},
function() {
info("Running step 3");
for (let i = 1; i < gBrowser.tabs.length; i++)
loadTab(gBrowser.tabs[i], TEST_URL_BASES[0] + gTabCounter);
},
function() {
info("Running step 4");
let ps = Services.prefs;
ps.setBoolPref("browser.privatebrowsing.keep_current_session", true);
ps.setBoolPref("browser.tabs.warnOnClose", false);
gPrivateBrowsing.privateBrowsingEnabled = true;
executeSoon(function() {
ensure_opentabs_match_db();
nextStep();
});
},
function() {
info("Running step 5");
gPrivateBrowsing.privateBrowsingEnabled = false;
executeSoon(function() {
let ps = Services.prefs;
try {
ps.clearUserPref("browser.privatebrowsing.keep_current_session");
} catch (ex) {}
try {
ps.clearUserPref("browser.tabs.warnOnClose");
} catch (ex) {}
ensure_opentabs_match_db();
nextStep()
});
}
];
function test() {
waitForExplicitFinish();
nextStep();
}
function loadTab(tab, url) {
tab.linkedBrowser.addEventListener("load", function (event) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
if (--gTabWaitCount > 0)
return;
is(gTabWaitCount, 0,
"sanity check, gTabWaitCount should not be decremented below 0");
try {
ensure_opentabs_match_db();
} catch (e) {
ok(false, "exception from ensure_openpages_match_db: " + e);
}
executeSoon(nextStep);
}, true);
gTabWaitCount++;
tab.linkedBrowser.loadURI(url);
}
function nextStep() {
if (gTestSteps.length == 0) {
while (gBrowser.tabs.length > 1) {
gBrowser.selectTabAtIndex(1);
gBrowser.removeCurrentTab();
}
waitForClearHistory(finish);
return;
}
var stepFunc = gTestSteps.shift();
stepFunc();
}
function ensure_opentabs_match_db() {
var tabs = {};
var winEnum = Services.wm.getEnumerator("navigator:browser");
while (winEnum.hasMoreElements()) {
let browserWin = winEnum.getNext();
// skip closed-but-not-destroyed windows
if (browserWin.closed)
continue;
for (let i = 0; i < browserWin.gBrowser.tabContainer.childElementCount; i++) {
let browser = browserWin.gBrowser.getBrowserAtIndex(i);
let url = browser.currentURI.spec;
if (!(url in tabs))
tabs[url] = 1;
else
tabs[url]++;
}
}
var db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.DBConnection;
try {
var stmt = db.createStatement(
"SELECT IFNULL(p_t.url, p.url) AS url, open_count, place_id " +
"FROM moz_openpages_temp " +
"LEFT JOIN moz_places p ON p.id=place_id " +
"LEFT JOIN moz_places_temp p_t ON p_t.id=place_id");
} catch (e) {
ok(false, "error creating db statement: " + e);
return;
}
var dbtabs = [];
try {
while (stmt.executeStep()) {
ok(stmt.row.url in tabs,
"url is in db, should be in tab: " + stmt.row.url);
is(tabs[stmt.row.url], stmt.row.open_count,
"db count (" + stmt.row.open_count + ") " +
"should match actual open tab count " +
"(" + tabs[stmt.row.url] + "): " + stmt.row.url);
dbtabs.push(stmt.row.url);
}
} finally {
stmt.finalize();
}
for (let url in tabs) {
// ignore URLs that should never be in the places db
if (!is_expected_in_db(url))
continue;
ok(dbtabs.indexOf(url) > -1,
"tab is open (" + tabs[url] + " times) and should recorded in db: " + url);
}
}
function is_expected_in_db(url) {
var uri = Services.io.newURI(url, null, null);
return PlacesUtils.history.canAddURI(uri);
}
/**
* Clears history invoking callback when done.
*/
function waitForClearHistory(aCallback) {
const TOPIC_EXPIRATION_FINISHED = "places-expiration-finished";
let observer = {
observe: function(aSubject, aTopic, aData) {
Services.obs.removeObserver(this, TOPIC_EXPIRATION_FINISHED);
aCallback();
}
};
Services.obs.addObserver(observer, TOPIC_EXPIRATION_FINISHED, false);
let hs = Cc["@mozilla.org/browser/nav-history-service;1"].
getService(Ci.nsINavHistoryService);
hs.QueryInterface(Ci.nsIBrowserHistory).removeAllPages();
}

Просмотреть файл

@ -61,8 +61,8 @@
this.inputField.addEventListener("mousedown", this, false);
this.inputField.addEventListener("mousemove", this, false);
this.inputField.addEventListener("mouseout", this, false);
this.inputField.addEventListener("overflow", this, false);
this.inputField.addEventListener("underflow", this, false);
this.inputField.addEventListener("overflow", this, false);
this.inputField.addEventListener("underflow", this, false);
]]></constructor>
<destructor><![CDATA[
@ -72,10 +72,45 @@
this.inputField.removeEventListener("mousedown", this, false);
this.inputField.removeEventListener("mousemove", this, false);
this.inputField.removeEventListener("mouseout", this, false);
this.inputField.removeEventListener("overflow", this, false);
this.inputField.removeEventListener("underflow", this, false);
this.inputField.removeEventListener("overflow", this, false);
this.inputField.removeEventListener("underflow", this, false);
]]></destructor>
<field name="_value"></field>
<!--
onBeforeValueGet is called by the base-binding's .value getter.
It can return an object with a "value" property, to override the
return value of the getter.
-->
<method name="onBeforeValueGet">
<body><![CDATA[
if (this.hasAttribute("actiontype"))
return {value: this._value};
return null;
]]></body>
</method>
<!--
onBeforeValueSet is called by the base-binding's .value setter.
It should return the value that the setter should use.
-->
<method name="onBeforeValueSet">
<parameter name="aValue"/>
<body><![CDATA[
this._value = aValue;
var returnValue = aValue;
var action = this._parseActionUrl(aValue);
if (action) {
returnValue = action.param;
this.setAttribute("actiontype", action.type);
} else {
this.removeAttribute("actiontype");
}
return returnValue;
]]></body>
</method>
<method name="handleRevert">
<body><![CDATA[
var isScrolling = this.popupOpen;
@ -108,6 +143,13 @@
if (!url)
return;
var action = this._parseActionUrl(url);
if (action) {
if (action.type == "switchtab")
switchToTabHavingURI(action.param);
return;
}
this.value = url;
gBrowser.userTypedValue = url;
try {
@ -216,12 +258,12 @@
return [url, postData.value];
]]></body>
</method>
<field name="_contentIsCropped">false</field>
<field name="_contentIsCropped">false</field>
<method name="_initURLTooltip">
<body><![CDATA[
if (this.focused || !this._contentIsCropped)
if (this.focused || !this._contentIsCropped)
return;
if (this._tooltipTimer)
clearTimeout(this._tooltipTimer);
@ -389,13 +431,13 @@
case "mouseout":
this._hideURLTooltip();
break;
case "overflow":
this._contentIsCropped = true;
break;
case "underflow":
this._contentIsCropped = false;
this._hideURLTooltip();
break;
case "overflow":
this._contentIsCropped = true;
break;
case "underflow":
this._contentIsCropped = false;
this._hideURLTooltip();
break;
}
]]></body>
</method>
@ -442,6 +484,18 @@
this.placeholder = this.getAttribute(type + "placeholder");
]]></body>
</method>
<method name="_parseActionUrl">
<parameter name="aUrl"/>
<body><![CDATA[
if (!/^moz-action:/.test(aUrl))
return null;
// url is in the format moz-action:ACTION,PARAM
let [, action, param] = aUrl.match(/^moz-action:([^,]+),(.*)$/);
return {type: action, param: param};
]]></body>
</method>
</implementation>
<handlers>
@ -613,6 +667,15 @@
this.closePopup();
controller.handleEscape();
// Check if this is meant to be an action
let action = this.mInput._parseActionUrl(url);
if (action) {
if (action.type == "switchtab")
url = action.param;
else
return;
}
// respect the usual clicking subtleties
openUILink(url, aEvent);
}
@ -640,4 +703,5 @@
</implementation>
</binding>
</bindings>

Просмотреть файл

@ -147,7 +147,7 @@ PlacesTreeView.prototype = {
* node which isn't supposed to be in the tree (e.g. separators in
* sorted trees).
* @param [optional] aForceBuild
* @see isPlainContainer.
* @see _isPlainContainer.
* If true, the row will be computed even if the node still isn't set
* in our rows array.
* @param [optional] aParentRow
@ -255,8 +255,6 @@ PlacesTreeView.prototype = {
return this._rows[aRow] = parent.getChild(aRow - parentRow - 1);
},
_rootNode: null,
/**
* This takes a container and recursively appends our rows array per its
* contents. Assumes that the rows arrays has no rows for the given
@ -284,9 +282,8 @@ PlacesTreeView.prototype = {
// iteration.
let cc = aContainer.childCount;
let newElements = new Array(cc);
this._rows =
this._rows.slice(0, aFirstChildRow).concat(newElements)
.concat(this._rows.slice(aFirstChildRow, this._rows.length));
this._rows = this._rows.splice(0, aFirstChildRow)
.concat(newElements, this._rows);
if (this._isPlainContainer(aContainer))
return cc;
@ -295,12 +292,12 @@ PlacesTreeView.prototype = {
const trueLiteral = PlacesUIUtils.RDF.GetLiteral("true");
let sortingMode = this._result.sortingMode;
let rowsInsertedCounter = 0;
let rowsInserted = 0;
for (let i = 0; i < cc; i++) {
let curChild = aContainer.getChild(i);
let curChildType = curChild.type;
let row = aFirstChildRow + rowsInsertedCounter;
let row = aFirstChildRow + rowsInserted;
// Don't display separators when sorted.
if (curChildType == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR) {
@ -314,7 +311,7 @@ PlacesTreeView.prototype = {
}
this._rows[row] = curChild;
rowsInsertedCounter++;
rowsInserted++;
// Recursively do containers.
if (!this._flatList &&
@ -327,12 +324,12 @@ PlacesTreeView.prototype = {
if (isopen != curChild.containerOpen)
aToOpen.push(curChild);
else if (curChild.containerOpen && curChild.childCount > 0)
rowsAddedCounter += this._buildVisibleSection(curChild, aToOpen,
row + 1);
rowsInserted += this._buildVisibleSection(curChild, aToOpen,
row + 1);
}
}
return rowsInsertedCounter;
return rowsInserted;
},
/**
@ -343,9 +340,9 @@ PlacesTreeView.prototype = {
function PTV__countVisibleRowsForNodeAtRow(aNodeRow) {
let node = this._rows[aNodeRow];
// If it's not listed yet, we know that it's a leaf node.
if (node === undefined ||
!(node instanceof Ci.nsINavHistoryContainerResultNode))
// If it's not listed yet, we know that it's a leaf node (instanceof also
// null-checks).
if (!(node instanceof Ci.nsINavHistoryContainerResultNode))
return 1;
let outerLevel = node.indentLevel;
@ -415,12 +412,16 @@ PlacesTreeView.prototype = {
let parent = aOldNode.parent;
if (parent) {
// If the node's parent is still set, the node is not obsolete
// and we should just find out its new position. However, if the node's
// parent is closed, the node is invisible.
if (parent.containerOpen)
return this._getRowForNode(aOldNode, true);
// and we should just find out its new position.
// However, if any of the node's ancestor is closed, the node is
// invisible.
let ancestors = PlacesUtils.nodeAncestors(aOldNode);
for (let ancestor in ancestors) {
if (!ancestor.containerOpen)
return -1;
}
return -1;
return this._getRowForNode(aOldNode, true);
}
// There's a broken edge case here.
@ -472,7 +473,7 @@ PlacesTreeView.prototype = {
// If only one node was previously selected and there's no selection now,
// select the node at its old row, if any.
if (aNodesInfo.length == 1 && selection.getRangeCount() == 0) {
if (aNodesInfo.length == 1 && selection.count == 0) {
let row = Math.min(aNodesInfo[0].oldRow, this._rows.length - 1);
selection.rangedSelect(row, row, true);
if (aNodesInfo[0].wasVisible && scrollToRow == -1)
@ -1105,7 +1106,7 @@ PlacesTreeView.prototype = {
isContainer: function PTV_isContainer(aRow) {
// Only leaf nodes aren't listed in the rows array.
let node = this._rows[aRow];
if (!node)
if (node === undefined)
return false;
if (PlacesUtils.nodeIsContainer(node)) {
@ -1568,6 +1569,7 @@ function PlacesTreeView(aFlatList, aOnOpenFlatContainer) {
this._tree = null;
this._result = null;
this._selection = null;
this._rootNode = null;
this._rows = [];
this._flatList = aFlatList;
this._openContainerCallback = aOnOpenFlatContainer;

Просмотреть файл

@ -196,7 +196,6 @@
#endif
@BINPATH@/components/locale.xpt
@BINPATH@/components/lwbrk.xpt
@BINPATH@/components/microsummaries.xpt
#ifndef WINCE
@BINPATH@/components/migration.xpt
#endif

Просмотреть файл

@ -731,7 +731,6 @@ components/layout_xul_tree.xpt
components/locale.xpt
components/loginmgr.xpt
components/lwbrk.xpt
components/microsummaries.xpt
components/migration.xpt
components/mimetype.xpt
components/mozbrwsr.xpt
@ -842,3 +841,4 @@ components/nsUpdateServiceStub.js
#endif
@DLL_PREFIX@sqlite3@DLL_SUFFIX@
old-homepage-default.properties
components/microsummaries.xpt

Просмотреть файл

@ -207,6 +207,7 @@
<!ENTITY urlbar.history.emptyText "Search History">
<!ENTITY urlbar.none.emptyText "Type a Web address">
<!ENTITY urlbar.accesskey "d">
<!ENTITY urlbar.switchToTab.label "Switch to tab:">
<!--
Comment duplicated from browser-sets.inc:

Двоичные данные
browser/themes/gnomestripe/browser/actionicon-tab.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 293 B

Просмотреть файл

@ -800,6 +800,17 @@ toolbar[iconsize="small"] #fullscreen-button {
display: none;
}
#urlbar-display {
margin-top: -2px;
margin-bottom: -2px;
padding-top: 3px;
padding-bottom: 2px;
-moz-padding-end: 3px;
color: GrayText;
-moz-border-end: 1px solid #AAA;
-moz-margin-end: 3px;
}
#PopupAutoComplete,
#PopupAutoCompleteRichResult {
direction: ltr !important;
@ -998,6 +1009,10 @@ toolbar[iconsize="small"] #fullscreen-button {
color: -moz-nativehyperlinktext;
}
richlistitem[type="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
list-style-image: url("chrome://browser/skin/actionicon-tab.png");
}
.autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
color: GrayText;
}

Просмотреть файл

@ -6,6 +6,7 @@ browser.jar:
* skin/classic/browser/aboutSessionRestore.css (aboutSessionRestore.css)
skin/classic/browser/aboutSessionRestore-window-icon.png
skin/classic/browser/aboutCertError.css (aboutCertError.css)
skin/classic/browser/actionicon-tab.png
* skin/classic/browser/browser.css (browser.css)
* skin/classic/browser/engineManager.css (engineManager.css)
skin/classic/browser/fullscreen-video.css

Двоичные данные
browser/themes/pinstripe/browser/actionicon-tab.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 293 B

Просмотреть файл

@ -868,6 +868,17 @@ toolbar[iconsize="small"] #unified-back-forward-button > #back-forward-dropmarke
width: 10px;
}
#urlbar-display {
margin-top: -2px;
margin-bottom: -2px;
padding-top: 3px;
padding-bottom: 2px;
-moz-padding-end: 3px;
color: GrayText;
-moz-border-end: 1px solid #AAA;
-moz-margin-end: 3px;
}
#PopupAutoCompleteRichResult {
direction: ltr !important;
margin-top: 2px;
@ -929,6 +940,10 @@ richlistitem[selected="true"][current="true"] > hbox > .ac-result-type-bookmark,
font-size: 0.95em;
}
richlistitem[type="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
list-style-image: url("chrome://browser/skin/actionicon-tab.png");
}
.autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
color: GrayText;
}

Просмотреть файл

@ -5,6 +5,7 @@ browser.jar:
* skin/classic/browser/aboutSessionRestore.css (aboutSessionRestore.css)
skin/classic/browser/aboutSessionRestore-window-icon.png
skin/classic/browser/aboutCertError.css (aboutCertError.css)
skin/classic/browser/actionicon-tab.png
* skin/classic/browser/browser.css (browser.css)
* skin/classic/browser/engineManager.css (engineManager.css)
skin/classic/browser/feed-icons.png

Двоичные данные
browser/themes/winstripe/browser/actionicon-tab.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 293 B

Просмотреть файл

@ -610,6 +610,17 @@ toolbar:not([iconsize="small"])[mode="icons"] #forward-button:not([disabled="tru
-moz-box-align: stretch;
}
#urlbar-display {
margin-top: -2px;
margin-bottom: -2px;
padding-top: 3px;
padding-bottom: 2px;
-moz-padding-end: 3px;
color: GrayText;
-moz-border-end: 1px solid #AAA;
-moz-margin-end: 3px;
}
/* identity box */
#identity-box {
@ -766,6 +777,10 @@ toolbar:not([iconsize="small"])[mode="icons"] #forward-button:not([disabled="tru
color: #006600;
}
richlistitem[type="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
list-style-image: url("chrome://browser/skin/actionicon-tab.png");
}
.autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
color: GrayText;
}

Просмотреть файл

@ -8,6 +8,7 @@ browser.jar:
* skin/classic/browser/aboutSessionRestore.css (aboutSessionRestore.css)
skin/classic/browser/aboutSessionRestore-window-icon.png (aboutSessionRestore-window-icon.png)
skin/classic/browser/aboutCertError.css (aboutCertError.css)
skin/classic/browser/actionicon-tab.png
* skin/classic/browser/browser.css (browser.css)
* skin/classic/browser/engineManager.css (engineManager.css)
skin/classic/browser/fullscreen-video.css
@ -93,6 +94,7 @@ browser.jar:
* skin/classic/aero/browser/aboutSessionRestore.css (aboutSessionRestore.css)
skin/classic/aero/browser/aboutSessionRestore-window-icon.png (aboutSessionRestore-window-icon-aero.png)
skin/classic/aero/browser/aboutCertError.css (aboutCertError.css)
skin/classic/aero/browser/actionicon-tab.png (actionicon-tab.png)
* skin/classic/aero/browser/browser.css (browser-aero.css)
* skin/classic/aero/browser/engineManager.css (engineManager.css)
skin/classic/aero/browser/fullscreen-video.css

Просмотреть файл

@ -63,10 +63,49 @@ struct ParamTraits<mozilla::plugins::NPRemoteEvent>
static void Write(Message* aMsg, const paramType& aParam)
{
// Make a non-const copy of aParam so that we can muck with
// its insides for transport
paramType paramCopy;
paramCopy.event = aParam.event;
switch (paramCopy.event.type) {
case NPCocoaEventMouseDown:
case NPCocoaEventMouseUp:
case NPCocoaEventMouseMoved:
case NPCocoaEventMouseEntered:
case NPCocoaEventMouseExited:
case NPCocoaEventMouseDragged:
case NPCocoaEventFocusChanged:
case NPCocoaEventWindowFocusChanged:
case NPCocoaEventScrollWheel:
// Nothing special to do for these events.
break;
case NPCocoaEventDrawRect:
// Don't serialize the context pointer
paramCopy.event.data.draw.context = NULL;
break;
case NPCocoaEventKeyDown:
case NPCocoaEventKeyUp:
case NPCocoaEventFlagsChanged:
case NPCocoaEventTextInput:
default:
// ignore any events we don't expect
return;
}
aMsg->WriteBytes(&paramCopy, sizeof(paramType));
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
const char* bytes = 0;
if (!aMsg->ReadBytes(aIter, &bytes, sizeof(paramType))) {
return false;
}
memcpy(aResult, bytes, sizeof(paramType));
return true;
}

Просмотреть файл

@ -50,6 +50,7 @@ using NPRemoteWindow;
using NPRemoteEvent;
using NPRect;
using NPNURLVariable;
using NPCoordinateSpace;
using mozilla::plugins::NativeWindowHandle;
namespace mozilla {
@ -79,6 +80,9 @@ child:
rpc NPP_HandleEvent(NPRemoteEvent event)
returns (int16_t handled);
// special cases where we need to a shared memory buffer
rpc NPP_HandleEvent_Shmem(NPRemoteEvent event, Shmem buffer)
returns (int16_t handled, Shmem rtnbuffer);
// special cases of HandleEvent to make mediating races simpler
rpc Paint(NPRemoteEvent event)
returns (int16_t handled);
@ -106,6 +110,10 @@ parent:
returns (NPError result);
rpc NPN_SetValue_NPPVpluginTransparent(bool transparent)
returns (NPError result);
rpc NPN_SetValue_NPPVpluginDrawingModel(int drawingModel)
returns (NPError result);
rpc NPN_SetValue_NPPVpluginEventModel(int eventModel)
returns (NPError result);
rpc NPN_GetURL(nsCString url, nsCString target)
returns (NPError result);
@ -139,6 +147,10 @@ parent:
nsCString realm)
returns (nsCString username, nsCString password, NPError result);
rpc NPN_ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
NPCoordinateSpace destSpace)
returns (double destX, bool ignoreDestX, double destY, bool ignoreDestY, bool result);
both:
async PPluginScriptableObject();

Просмотреть файл

@ -80,6 +80,7 @@ child:
returns (NPError rv);
parent:
async XXX_HACK_FIXME_cjones(Shmem _);
rpc NPN_UserAgent()
returns (nsCString userAgent);

Просмотреть файл

@ -77,8 +77,9 @@ using mozilla::gfx::SharedDIB;
#include <windowsx.h>
#define NS_OOPP_DOUBLEPASS_MSGID TEXT("MozDoublePassMsg")
#endif // defined(OS_WIN)
#elif defined(XP_MACOSX)
#include <ApplicationServices/ApplicationServices.h>
#endif // defined(XP_MACOSX)
PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface,
const nsCString& aMimeType)
@ -320,6 +321,30 @@ PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
#endif
}
#ifdef XP_MACOSX
case NPNVsupportsCoreGraphicsBool: {
*((NPBool*)aValue) = true;
return NPERR_NO_ERROR;
}
case NPNVsupportsCoreAnimationBool: {
*((NPBool*)aValue) = false;
return NPERR_NO_ERROR;
}
case NPNVsupportsCocoaBool: {
*((NPBool*)aValue) = true;
return NPERR_NO_ERROR;
}
#ifndef NP_NO_QUICKDRAW
case NPNVsupportsQuickDrawBool: {
*((NPBool*)aValue) = false;
return NPERR_NO_ERROR;
}
#endif /* NP_NO_QUICKDRAW */
#endif /* XP_MACOSX */
default:
PR_LOG(gPluginLog, PR_LOG_WARNING,
("In PluginInstanceChild::NPN_GetValue: Unhandled NPNVariable %i (%s)",
@ -359,6 +384,28 @@ PluginInstanceChild::NPN_SetValue(NPPVariable aVar, void* aValue)
return rv;
}
#ifdef XP_MACOSX
case NPPVpluginDrawingModel: {
NPError rv;
int drawingModel = (int16) (intptr_t) aValue;
if (!CallNPN_SetValue_NPPVpluginDrawingModel(drawingModel, &rv))
return NPERR_GENERIC_ERROR;
return rv;
}
case NPPVpluginEventModel: {
NPError rv;
int eventModel = (int16) (intptr_t) aValue;
if (!CallNPN_SetValue_NPPVpluginEventModel(eventModel, &rv))
return NPERR_GENERIC_ERROR;
return rv;
}
#endif
default:
PR_LOG(gPluginLog, PR_LOG_WARNING,
("In PluginInstanceChild::NPN_SetValue: Unhandled NPPVariable %i (%s)",
@ -464,7 +511,7 @@ PluginInstanceChild::AnswerNPP_HandleEvent(const NPRemoteEvent& event,
event.event.xgraphicsexpose.drawable));
#endif
#ifdef OS_MACOSX
#ifdef XP_MACOSX
// Mac OS X does not define an NPEvent structure. It defines more specific types.
NPCocoaEvent evcopy = event.event;
#else
@ -513,6 +560,73 @@ PluginInstanceChild::AnswerNPP_HandleEvent(const NPRemoteEvent& event,
return true;
}
#ifdef XP_MACOSX
bool
PluginInstanceChild::AnswerNPP_HandleEvent_Shmem(const NPRemoteEvent& event,
Shmem& mem,
int16_t* handled,
Shmem* rtnmem)
{
PLUGIN_LOG_DEBUG_FUNCTION;
AssertPluginThread();
// We return access to the shared memory buffer after returning.
NPCocoaEvent evcopy = event.event;
if (evcopy.type == NPCocoaEventDrawRect) {
CGColorSpaceRef cSpace = ::CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
if (!cSpace) {
PLUGIN_LOG_DEBUG(("Could not allocate ColorSpace."));
*handled = false;
*rtnmem = mem;
return true;
}
void* cgContextByte = mem.get<char>();
CGContextRef ctxt = ::CGBitmapContextCreate(cgContextByte, mWindow.width, mWindow.height, 8, mWindow.width * 4, cSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
::CGColorSpaceRelease(cSpace);
if (!ctxt) {
PLUGIN_LOG_DEBUG(("Could not allocate CGBitmapContext."));
*handled = false;
*rtnmem = mem;
return true;
}
evcopy.data.draw.context = ctxt;
} else {
PLUGIN_LOG_DEBUG(("Invalid event type for AnswerNNP_HandleEvent_Shmem."));
*handled = false;
*rtnmem = mem;
return true;
}
if (!mPluginIface->event) {
*handled = false;
} else {
*handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy));
}
// Some events need cleaning up.
if (evcopy.type == NPCocoaEventDrawRect) {
::CGContextRelease(evcopy.data.draw.context);
}
*rtnmem = mem;
return true;
}
#else
bool
PluginInstanceChild::AnswerNPP_HandleEvent_Shmem(const NPRemoteEvent& event,
Shmem& mem,
int16_t* handled,
Shmem* rtnmem)
{
NS_RUNTIMEABORT("not reached.");
*rtnmem = mem;
return true;
}
#endif
bool
PluginInstanceChild::RecvWindowPosChanged(const NPRemoteEvent& event)
{
@ -641,7 +755,7 @@ PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
break;
}
#elif defined(OS_MACOSX)
#elif defined(XP_MACOSX)
mWindow.x = aWindow.x;
mWindow.y = aWindow.y;
@ -650,6 +764,9 @@ PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
mWindow.clipRect = aWindow.clipRect;
mWindow.type = aWindow.type;
if (mPluginIface->setwindow)
(void) mPluginIface->setwindow(&mData, &mWindow);
#else
# error Implement me for your OS
#endif

Просмотреть файл

@ -88,6 +88,8 @@ protected:
virtual bool
AnswerNPP_HandleEvent(const NPRemoteEvent& event, int16_t* handled);
virtual bool
AnswerNPP_HandleEvent_Shmem(const NPRemoteEvent& event, Shmem& mem, int16_t* handled, Shmem* rtnmem);
NS_OVERRIDE
virtual bool

Просмотреть файл

@ -59,7 +59,9 @@ UINT gOOPPStopNativeLoopEvent =
RegisterWindowMessage(L"SyncChannel Stop Inner Loop Message");
#elif defined(MOZ_WIDGET_GTK2)
#include <gdk/gdk.h>
#endif
#elif defined(XP_MACOSX)
#include <ApplicationServices/ApplicationServices.h>
#endif // defined(XP_MACOSX)
using namespace mozilla::plugins;
@ -75,6 +77,10 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
, mPluginWndProc(NULL)
, mNestedEventState(false)
#endif // defined(XP_WIN)
#if defined(XP_MACOSX)
, mShWidth(0)
, mShHeight(0)
#endif
{
}
@ -293,7 +299,6 @@ PluginInstanceParent::AnswerNPN_GetValue_NPNVprivateModeBool(bool* value,
return true;
}
bool
PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginWindow(
const bool& windowed, NPError* result)
@ -314,6 +319,33 @@ PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginTransparent(
return true;
}
bool
PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginDrawingModel(
const int& drawingModel, NPError* result)
{
#ifdef XP_MACOSX
*result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
(void*)drawingModel);
return true;
#else
*result = NPERR_GENERIC_ERROR;
return true;
#endif
}
bool
PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginEventModel(
const int& eventModel, NPError* result)
{
#ifdef XP_MACOSX
*result = mNPNIface->setvalue(mNPP, NPPVpluginEventModel,
(void*)eventModel);
return true;
#else
*result = NPERR_GENERIC_ERROR;
return true;
#endif
}
bool
PluginInstanceParent::AnswerNPN_GetURL(const nsCString& url,
@ -438,6 +470,20 @@ PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
window.type = aWindow->type;
#endif
#if defined(XP_MACOSX)
if (mShWidth * mShHeight != window.width * window.height) {
// XXX: benwa: OMG MEMORY LEAK!
// There is currently no way dealloc the shmem
// so for now we will leak the memory and will fix this ASAP!
if (!AllocShmem(window.width * window.height * 4, &mShSurface)) {
PLUGIN_LOG_DEBUG(("Shared memory could not be allocated."));
return NPERR_GENERIC_ERROR;
}
mShWidth = window.width;
mShHeight = window.height;
}
#endif
#if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
const NPSetWindowCallbackStruct* ws_info =
static_cast<NPSetWindowCallbackStruct*>(aWindow->ws_info);
@ -626,6 +672,52 @@ PluginInstanceParent::NPP_HandleEvent(void* event)
}
#endif
#ifdef XP_MACOSX
if (npevent->type == NPCocoaEventDrawRect) {
if (mShWidth == 0 && mShHeight == 0) {
PLUGIN_LOG_DEBUG(("NPCocoaEventDrawRect on window of size 0."));
return false;
}
if (!mShSurface.IsReadable()) {
PLUGIN_LOG_DEBUG(("Shmem is not readable."));
return false;
}
if (!CallNPP_HandleEvent_Shmem(npremoteevent, mShSurface, &handled, &mShSurface))
return false; // no good way to handle errors here...
if (!mShSurface.IsReadable()) {
PLUGIN_LOG_DEBUG(("Shmem not returned. Either the plugin crashed or we have a bug."));
return false;
}
char* shContextByte = mShSurface.get<char>();
CGColorSpaceRef cSpace = ::CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
if (!cSpace) {
PLUGIN_LOG_DEBUG(("Could not allocate ColorSpace."));
return true;
}
CGContextRef shContext = ::CGBitmapContextCreate(shContextByte,
mShWidth, mShHeight, 8, mShWidth*4, cSpace,
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
::CGColorSpaceRelease(cSpace);
if (!shContext) {
PLUGIN_LOG_DEBUG(("Could not allocate CGBitmapContext."));
return true;
}
CGImageRef shImage = ::CGBitmapContextCreateImage(shContext);
if (shImage) {
CGContextRef cgContext = npevent->data.draw.context;
::CGContextDrawImage(cgContext, CGRectMake(0,0,mShWidth,mShHeight), shImage);
::CGImageRelease(shImage);
}
::CGContextRelease(shContext);
return handled;
}
#endif
if (!CallNPP_HandleEvent(npremoteevent, &handled))
return 0; // no good way to handle errors here...
@ -898,13 +990,32 @@ PluginInstanceParent::AnswerNPN_GetAuthenticationInfo(const nsCString& protocol,
return true;
}
bool
PluginInstanceParent::AnswerNPN_ConvertPoint(const double& sourceX,
const double& sourceY,
const NPCoordinateSpace& sourceSpace,
const NPCoordinateSpace& destSpace,
double *destX,
bool *ignoreDestX,
double *destY,
bool *ignoreDestY,
bool *result)
{
*result = mNPNIface->convertpoint(mNPP, sourceX, sourceY, sourceSpace,
ignoreDestX ? nsnull : destX,
ignoreDestY ? nsnull : destY,
destSpace);
return true;
}
#if defined(OS_WIN)
/*
plugin focus changes between processes
focus from dom -> child:
Focs manager calls on widget to set the focus on the window.
Focus manager calls on widget to set the focus on the window.
We pick up the resulting wm_setfocus event here, and forward
that over ipc to the child which calls set focus on itself.

Просмотреть файл

@ -126,6 +126,12 @@ public:
virtual bool
AnswerNPN_SetValue_NPPVpluginTransparent(const bool& transparent,
NPError* result);
virtual bool
AnswerNPN_SetValue_NPPVpluginDrawingModel(const int& drawingModel,
NPError* result);
virtual bool
AnswerNPN_SetValue_NPPVpluginEventModel(const int& eventModel,
NPError* result);
virtual bool
AnswerNPN_GetURL(const nsCString& url, const nsCString& target,
@ -182,6 +188,17 @@ public:
nsCString* password,
NPError* result);
NS_OVERRIDE virtual bool
AnswerNPN_ConvertPoint(const double& sourceX,
const double& sourceY,
const NPCoordinateSpace& sourceSpace,
const NPCoordinateSpace& destSpace,
double *destX,
bool *ignoreDestX,
double *destY,
bool *ignoreDestY,
bool *result);
NPError NPP_SetWindow(const NPWindow* aWindow);
NPError NPP_GetValue(NPPVariable variable, void* retval);
@ -263,6 +280,12 @@ private:
WNDPROC mPluginWndProc;
bool mNestedEventState;
#endif // defined(XP_WIN)
#if defined(OS_MACOSX)
private:
Shmem mShSurface;
size_t mShWidth;
size_t mShHeight;
#endif // definied(OS_MACOSX)
};

Просмотреть файл

@ -676,6 +676,35 @@ struct ParamTraits<NPNURLVariable>
}
};
template<>
struct ParamTraits<NPCoordinateSpace>
{
typedef NPCoordinateSpace paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, int32(aParam));
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
int32 intval;
if (ReadParam(aMsg, aIter, &intval)) {
switch (intval) {
case NPCoordinateSpacePlugin:
case NPCoordinateSpaceWindow:
case NPCoordinateSpaceFlippedWindow:
case NPCoordinateSpaceScreen:
case NPCoordinateSpaceFlippedScreen:
*aResult = paramType(intval);
return true;
}
}
return false;
}
};
} /* namespace IPC */

Просмотреть файл

@ -1451,8 +1451,22 @@ _convertpoint(NPP instance,
{
PLUGIN_LOG_DEBUG_FUNCTION;
AssertPluginThread();
NS_WARNING("Not yet implemented!");
return 0;
double rDestX = 0;
bool ignoreDestX = !destX;
double rDestY = 0;
bool ignoreDestY = !destY;
bool result = false;
InstCast(instance)->CallNPN_ConvertPoint(sourceX, sourceY, sourceSpace, destSpace,
&rDestX, &ignoreDestX, &rDestY, &ignoreDestY, &result);
if (result) {
if (destX)
*destX = rDestX;
if (destY)
*destY = rDestY;
}
return result;
}
} /* namespace child */

Просмотреть файл

@ -142,6 +142,8 @@ protected:
return MediateRace(parent, child);
}
virtual bool RecvXXX_HACK_FIXME_cjones(Shmem& mem) { NS_RUNTIMEABORT("not reached"); return false; }
NS_OVERRIDE
virtual bool ShouldContinueFromReplyTimeout();

Просмотреть файл

@ -107,4 +107,13 @@ interface mozIPlacesAutoComplete : nsISupports
* Search javascript: URLs.
*/
const long BEHAVIOR_JAVASCRIPT = 1 << 6;
/**
* Search for pages that have been marked as being opened, such as a tab
* in a tabbrowser, via:
* nsIBrowserHistory.registerOpenPage(url)
*
* @see nsIBrowserHistory.idl
*/
const long BEHAVIOR_OPENPAGE = 1 << 7;
};

Просмотреть файл

@ -42,7 +42,7 @@
#include "nsISupports.idl"
#include "nsIGlobalHistory2.idl"
[scriptable, uuid(124a8db3-59da-48ac-a563-6dcf58e035b4)]
[scriptable, uuid(540aca25-1e01-467f-b24c-df89cbe40f8d)]
interface nsIBrowserHistory : nsIGlobalHistory2
{
/**
@ -156,4 +156,18 @@ interface nsIBrowserHistory : nsIGlobalHistory2
* the user (for example by clicking on it).
*/
void markPageAsFollowedLink(in nsIURI aURI);
/**
* Mark a page as being currently open.
*/
void registerOpenPage(in nsIURI aURI);
/**
* Mark a page as no longer being open (either by closing the window or tab,
* or by navigating away from that page).
*
* Note that when Private Browsing mode is entered/exited, pages need to be
* manually unregistered/registered.
*/
void unregisterOpenPage(in nsIURI aURI);
};

Просмотреть файл

@ -2161,7 +2161,7 @@ function sanitizeName(aName) {
// If our input had not enough valid characters, use a random name.
if (name.length < MIN_GENERATOR_NAME_LENGTH)
name = Math.random().toString(36).substr(2);
name = Math.random().toString(36).replace(/^.*\./, '');
// Force max length.
return name.substring(0, MAX_GENERATOR_NAME_LENGTH);

Просмотреть файл

@ -991,6 +991,13 @@ nsNavHistory::InitTempTables()
rv = mDBConn->ExecuteSimpleSQL(CREATE_MOZ_HISTORYVISITS_SYNC_TRIGGER);
NS_ENSURE_SUCCESS(rv, rv);
// moz_openpages_temp
rv = mDBConn->ExecuteSimpleSQL(CREATE_MOZ_OPENPAGES_TEMP);
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->ExecuteSimpleSQL(CREATE_REMOVEOPENPAGE_CLEANUP_TRIGGER);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
@ -1217,6 +1224,27 @@ nsNavHistory::InitStatements()
"WHERE url = ?2"),
getter_AddRefs(mDBSetPlaceTitle));
NS_ENSURE_SUCCESS(rv, rv);
// mDBRegisterOpenPage
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"INSERT OR REPLACE INTO moz_openpages_temp (place_id, open_count) "
"VALUES (?1, "
"IFNULL("
"(SELECT open_count + 1 FROM moz_openpages_temp WHERE place_id = ?1), "
"1"
")"
")"),
getter_AddRefs(mDBRegisterOpenPage));
NS_ENSURE_SUCCESS(rv, rv);
// mDBUnregisterOpenPage
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"UPDATE moz_openpages_temp "
"SET open_count = open_count - 1 "
"WHERE place_id = ?1"),
getter_AddRefs(mDBUnregisterOpenPage));
NS_ENSURE_SUCCESS(rv, rv);
// mDBVisitsForFrecency
// NOTE: This is not limited to visits with "visit_type NOT IN (0,4,7,8)"
// because otherwise mDBVisitsForFrecency would return no visits
@ -5035,6 +5063,72 @@ nsNavHistory::MarkPageAsFollowedLink(nsIURI *aURI)
}
NS_IMETHODIMP
nsNavHistory::RegisterOpenPage(nsIURI* aURI)
{
NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
NS_ENSURE_ARG(aURI);
// Don't add any pages while in Private Browsing mode, so as to avoid leaking
// information about other windows that might otherwise stay hidden
// and private.
if (InPrivateBrowsingMode())
return NS_OK;
PRBool canAdd = PR_FALSE;
nsresult rv = CanAddURI(aURI, &canAdd);
NS_ENSURE_SUCCESS(rv, rv);
PRInt64 placeId;
// Note: If the URI has never been added to history (but can be added),
// LAZY_ADD will cause this to add an orphan page, until the visit is added.
rv = GetUrlIdFor(aURI, &placeId, canAdd);
NS_ENSURE_SUCCESS(rv, rv);
if (placeId == 0)
return NS_OK;
mozStorageStatementScoper scoper(mDBRegisterOpenPage);
rv = mDBRegisterOpenPage->BindInt64Parameter(0, placeId);
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBRegisterOpenPage->Execute();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsNavHistory::UnregisterOpenPage(nsIURI* aURI)
{
NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
NS_ENSURE_ARG(aURI);
// Entering Private Browsing mode will unregister all open pages, therefore
// there shouldn't be anything in the moz_openpages_temp table. So we can stop
// now without doing any unnecessary work.
if (InPrivateBrowsingMode())
return NS_OK;
PRInt64 placeId;
nsresult rv = GetUrlIdFor(aURI, &placeId, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
if (placeId == 0)
return NS_OK;
mozStorageStatementScoper scoper(mDBUnregisterOpenPage);
rv = mDBUnregisterOpenPage->BindInt64Parameter(0, placeId);
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBUnregisterOpenPage->Execute();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
// nsNavHistory::SetCharsetForURI
//
// Sets the character-set for a URI.
@ -8154,6 +8248,8 @@ nsNavHistory::FinalizeStatements() {
mDBUpdateFrecencyAndHidden,
mDBGetPlaceVisitStats,
mDBFullVisitCount,
mDBRegisterOpenPage,
mDBUnregisterOpenPage,
};
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(stmts); i++) {

Просмотреть файл

@ -427,6 +427,8 @@ protected:
nsCOMPtr<mozIStorageStatement> mDBGetTags; // used by GetTags
nsCOMPtr<mozIStorageStatement> mDBGetItemsWithAnno; // used by AutoComplete::StartSearch and FilterResultSet
nsCOMPtr<mozIStorageStatement> mDBSetPlaceTitle; // used by SetPageTitleInternal
nsCOMPtr<mozIStorageStatement> mDBRegisterOpenPage; // used by RegisterOpenPage
nsCOMPtr<mozIStorageStatement> mDBUnregisterOpenPage; // used by UnregisterOpenPage
// these are used by VisitIdToResultNode for making new result nodes from IDs
// Consumers need to use the getters since these statements are lazily created

Просмотреть файл

@ -94,6 +94,7 @@ const kQueryIndexVisitCount = 6;
const kQueryIndexTyped = 7;
const kQueryIndexPlaceId = 8;
const kQueryIndexQueryType = 9;
const kQueryIndexOpenPageCount = 10;
// AutoComplete query type constants. Describes the various types of queries
// that we can process.
@ -217,9 +218,11 @@ function nsPlacesAutoComplete()
// Note: h.frecency is only selected because we need it for ordering.
function sql_base_fragment(aTableName) {
return "SELECT h.url, h.title, f.url, " + kBookTagSQLFragment + ", " +
"h.visit_count, h.typed, h.id, :query_type, h.frecency " +
"h.visit_count, h.typed, h.id, :query_type, t.open_count, " +
"h.frecency " +
"FROM " + aTableName + " h " +
"LEFT OUTER JOIN moz_favicons f ON f.id = h.favicon_id " +
"LEFT OUTER JOIN moz_openpages_temp t ON t.place_id = h.id " +
"WHERE h.frecency <> 0 " +
"AND AUTOCOMPLETE_MATCH(:searchString, h.url, " +
"IFNULL(bookmark, h.title), tags, " +
@ -291,6 +294,13 @@ function nsPlacesAutoComplete()
);
});
XPCOMUtils.defineLazyGetter(this, "_openPagesQuery", function() {
let replacementText = "AND t.open_count > 0";
return this._db.createStatement(
SQL_BASE.replace("{ADDITIONAL_CONDITIONS}", replacementText, "g")
);
});
XPCOMUtils.defineLazyGetter(this, "_typedQuery", function() {
let replacementText = "AND h.typed = 1";
return this._db.createStatement(
@ -311,7 +321,7 @@ function nsPlacesAutoComplete()
kBookTagSQLFragment + ", " +
"IFNULL(h_t.visit_count, h.visit_count) AS c_visit_count, " +
"IFNULL(h_t.typed, h.typed) AS c_typed, " +
"IFNULL(h_t.id, h.id), :query_type, rank " +
"IFNULL(h_t.id, h.id), :query_type, t.open_count, rank " +
"FROM ( " +
"SELECT ROUND(MAX(((i.input = :search_string) + " +
"(SUBSTR(i.input, 1, LENGTH(:search_string)) = :search_string)) * " +
@ -323,6 +333,7 @@ function nsPlacesAutoComplete()
"LEFT JOIN moz_places h ON h.id = i.place_id " +
"LEFT JOIN moz_places_temp h_t ON h_t.id = i.place_id " +
"LEFT JOIN moz_favicons f ON f.id = IFNULL(h_t.favicon_id, h.favicon_id) " +
"LEFT JOIN moz_openpages_temp t ON t.place_id = i.place_id " +
"WHERE c_url NOTNULL " +
"AND AUTOCOMPLETE_MATCH(:searchString, c_url, " +
"IFNULL(bookmark, c_title), tags, " +
@ -343,12 +354,13 @@ function nsPlacesAutoComplete()
best_favicon_for_revhost("moz_places") + "), b.parent, " +
"b.title, NULL, IFNULL(h_t.visit_count, h.visit_count), " +
"IFNULL(h_t.typed, h.typed), COALESCE(h_t.id, h.id, b.fk), " +
":query_type " +
":query_type, t.open_count " +
"FROM moz_keywords k " +
"JOIN moz_bookmarks b ON b.keyword_id = k.id " +
"LEFT JOIN moz_places AS h ON h.url = search_url " +
"LEFT JOIN moz_places_temp AS h_t ON h_t.url = search_url " +
"LEFT JOIN moz_favicons f ON f.id = IFNULL(h_t.favicon_id, h.favicon_id) " +
"LEFT JOIN moz_openpages_temp t ON t.place_id = IFNULL(h_t.id, h.id) " +
"WHERE LOWER(k.keyword) = LOWER(:keyword) " +
"ORDER BY IFNULL(h_t.frecency, h.frecency) DESC"
);
@ -387,6 +399,9 @@ nsPlacesAutoComplete.prototype = {
this._currentSearchString =
this._fixupSearchText(this._originalSearchString.toLowerCase());
var searchParamParts = aSearchParam.split(" ");
this._enableActions = searchParamParts.indexOf("enable-actions") != -1;
this._listener = aListener;
let result = Cc["@mozilla.org/autocomplete/simple-result;1"].
createInstance(Ci.nsIAutoCompleteSimpleResult);
@ -519,6 +534,7 @@ nsPlacesAutoComplete.prototype = {
"_historyQuery",
"_bookmarkQuery",
"_tagsQuery",
"_openPagesQuery",
"_typedQuery",
"_adaptiveQuery",
"_keywordQuery",
@ -598,6 +614,7 @@ nsPlacesAutoComplete.prototype = {
delete this._usedPlaceIds;
delete this._pendingQuery;
this._secondPass = false;
this._enableActions = false;
},
/**
@ -680,13 +697,14 @@ nsPlacesAutoComplete.prototype = {
this._restrictBookmarkToken = safeGetter("restrict.bookmark", "*");
this._restrictTypedToken = safeGetter("restrict.typed", "~");
this._restrictTagToken = safeGetter("restrict.tag", "+");
this._restrictOpenPageToken = safeGetter("restrict.openpage", "%");
this._matchTitleToken = safeGetter("match.title", "#");
this._matchURLToken = safeGetter("match.url", "@");
this._defaultBehavior = safeGetter("default.behavior", 0);
// Further restrictions to apply for "empty searches" (i.e. searches for "").
// By default we use (HISTORY | TYPED) = 33.
// By default we use (HISTORY | TYPED | OPENPAGE) = 161.
this._emptySearchDefaultBehavior = this._defaultBehavior |
safeGetter("default.behavior.emptyRestriction", 33);
safeGetter("default.behavior.emptyRestriction", 161);
// Validate matchBehavior; default to MATCH_BOUNDARY_ANYWHERE.
if (this._matchBehavior != MATCH_ANYWHERE &&
@ -727,6 +745,11 @@ nsPlacesAutoComplete.prototype = {
case this._restrictTagToken:
this._setBehavior("tag");
break;
case this._restrictOpenPageToken:
if (!this._enableActions)
continue;
this._setBehavior("openpage");
break;
case this._matchTitleToken:
this._setBehavior("title");
break;
@ -780,6 +803,7 @@ nsPlacesAutoComplete.prototype = {
this._hasBehavior("bookmark") ? this._bookmarkQuery :
this._hasBehavior("typed") ? this._typedQuery :
this._hasBehavior("history") ? this._historyQuery :
this._hasBehavior("openpage") ? this._openPagesQuery :
this._defaultQuery;
// Bind the needed parameters to the query so consumers can use it.
@ -880,6 +904,7 @@ nsPlacesAutoComplete.prototype = {
let entryBookmarkTitle = entryParentId ?
aRow.getResultByIndex(kQueryIndexBookmarkTitle) : null;
let entryTags = aRow.getResultByIndex(kQueryIndexTags) || "";
let openPageCount = aRow.getResultByIndex(kQueryIndexOpenPageCount) || 0;
// Always prefer the bookmark title unless it is empty
let title = entryBookmarkTitle || entryTitle;
@ -926,8 +951,22 @@ nsPlacesAutoComplete.prototype = {
style = "favicon";
}
// And finally add this to our results.
this._addToResults(entryId, escapedEntryURL, title, entryFavicon, style);
// If actions aren't enabled, avoid doing any additional work.
if (!this._enableActions) {
this._addToResults(entryId, escapedEntryURL, title, entryFavicon, style);
return true;
}
// Add a special entry for an open-page match.
if ((this._hasBehavior("openpage") || this._hasBehavior("everything")) &&
openPageCount > 0)
this._addToResults(entryId, "moz-action:switchtab," + escapedEntryURL, title, entryFavicon, "action");
// If restricting to only open-page matches, there should only be the
// switch-to-tab results.
if (!this._onlyHasBehavior("openpage"))
this._addToResults(entryId, escapedEntryURL, title, entryFavicon, style);
return true;
},
@ -981,15 +1020,32 @@ nsPlacesAutoComplete.prototype = {
* Determines if the specified AutoComplete behavior is set.
*
* @param aType
* The behavior type to test for.
* The behavior type to test for, or "everything" to test if no
* specific behavior has been set.
* @return true if the behavior is set, false otherwise.
*/
_hasBehavior: function PAC_hasBehavior(aType)
{
if (aType == "everything")
return this._behavior == 0;
return (this._behavior &
Ci.mozIPlacesAutoComplete["BEHAVIOR_" + aType.toUpperCase()]);
},
/**
* Determines if the specified AutoComplete behavior is the only behavior set.
*
* @param aType
* The behavior type to test for.
* @return true if the behavior is set and no other behaviors are set,
* false otherwise.
*/
_onlyHasBehavior: function PAC_onlyHasBehavior(aType)
{
return (this._behavior ==
Ci.mozIPlacesAutoComplete["BEHAVIOR_" + aType.toUpperCase()]);
},
/**
* Enables the desired AutoComplete behavior.
*

Просмотреть файл

@ -177,4 +177,11 @@
")" \
)
#define CREATE_MOZ_OPENPAGES_TEMP NS_LITERAL_CSTRING( \
"CREATE TEMP TABLE moz_openpages_temp (" \
" place_id INTEGER PRIMARY KEY" \
", open_count INTEGER" \
")" \
)
#endif // __nsPlacesTables_h__

Просмотреть файл

@ -94,8 +94,8 @@
/**
* This trigger allows for the deletion of a record in moz_places_view. It
* removes any entry in the temporary table, and any entry in the permanent
* table as well.
* removes any entry in the temporary table, the permanent table, and any
* associated entry in moz_openpages_temp.
*/
#define CREATE_PLACES_VIEW_DELETE_TRIGGER NS_LITERAL_CSTRING( \
"CREATE TEMPORARY TRIGGER moz_places_view_delete_trigger " \
@ -106,6 +106,8 @@
"WHERE id = OLD.id; " \
"DELETE FROM moz_places " \
"WHERE id = OLD.id; " \
"DELETE FROM moz_openpages_temp " \
"WHERE place_id = OLD.id; " \
"END" \
)
@ -258,4 +260,18 @@
#define CREATE_MOZ_HISTORYVISITS_SYNC_TRIGGER \
CREATE_TEMP_SYNC_TRIGGER_BASE("moz_historyvisits", MOZ_HISTORYVISITS_COLUMNS)
/**
* This trigger removes a row from moz_openpages_temp when open_count reaches 0.
*/
#define CREATE_REMOVEOPENPAGE_CLEANUP_TRIGGER NS_LITERAL_CSTRING( \
"CREATE TEMPORARY TRIGGER moz_openpages_temp_afterupdate_trigger " \
"AFTER UPDATE OF open_count ON moz_openpages_temp FOR EACH ROW " \
"WHEN NEW.open_count = 0 " \
"BEGIN " \
"DELETE FROM moz_openpages_temp " \
"WHERE place_id = NEW.place_id;" \
"END" \
)
#endif // __nsPlacesTriggers_h__

Просмотреть файл

@ -266,6 +266,19 @@ var PlacesUtils = {
return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY;
},
/**
* Generator for a node's ancestors.
* @param aNode
* A result node
*/
nodeAncestors: function PU_nodeAncestors(aNode) {
let node = aNode.parent;
while (node) {
yield node;
node = node.parent;
}
},
/**
* Cache array of read-only item IDs.
*

Просмотреть файл

@ -99,6 +99,9 @@ function ensure_results(aSearch, aExpected)
controller.input = input;
if (typeof kSearchParam == "string")
input.searchParam = kSearchParam;
let numSearchesStarted = 0;
input.onSearchBegin = function() {
numSearchesStarted++;

Просмотреть файл

@ -0,0 +1,104 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim:set ts=2 sw=2 sts=2 et:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Places Test Code.
*
* The Initial Developer of the Original Code is the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Blair McBride <bmcbride@mozilla.com> (Original Author)
*
* 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
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
let gTabRestrictChar = prefs.getCharPref("browser.urlbar.restrict.openpage");
let kSearchParam = "enable-actions";
let kURIs = [
"http://abc.com/",
"moz-action:switchtab,http://abc.com/",
"http://xyz.net/",
"moz-action:switchtab,http://xyz.net/"
];
let kTitles = [
"ABC rocks",
"xyz.net - we're better than ABC"
];
addPageBook(0, 0);
gPages[1] = [1, 0];
addPageBook(2, 1);
gPages[3] = [3, 1];
addOpenPages(0, 1);
let gTests = [
["0: single result, that is also a tab match",
"abc.com", [0,1]],
["1: two results, one tab match",
"abc", [0,1,2]],
["2: two results, both tab matches",
"abc", [0,1,2,3],
function() {
addOpenPages(2, 1);
}],
["3: two results, both tab matches, one has multiple tabs",
"abc", [0,1,2,3],
function() {
addOpenPages(2, 5);
}],
["4: two results, no tab matches",
"abc", [0,2],
function() {
removeOpenPages(0, 1);
removeOpenPages(2, 6);
}],
["5: tab match search with restriction character",
gTabRestrictChar + " abc", [1],
function() {
addOpenPages(0, 1);
}]
];
function addOpenPages(aUri, aCount) {
let num = aCount || 1;
for (let i = 0; i < num; i++) {
bhist.registerOpenPage(toURI(kURIs[aUri]));
}
}
function removeOpenPages(aUri, aCount) {
let num = aCount || 1;
for (let i = 0; i < num; i++) {
bhist.unregisterOpenPage(toURI(kURIs[aUri]));
}
}

Просмотреть файл

@ -668,33 +668,23 @@ function getSanitizedFile(aName) {
}
/**
* Removes all characters not in the "chars" string from aName.
*
* @returns a sanitized name to be used as a filename, or a random name
* if a sanitized name cannot be obtained (if aName contains
* no valid characters).
* @return a sanitized name to be used as a filename, or a random name
* if a sanitized name cannot be obtained (if aName contains
* no valid characters).
*/
function sanitizeName(aName) {
const chars = "-abcdefghijklmnopqrstuvwxyz0123456789";
const maxLength = 60;
const minLength = 1;
var name = aName.toLowerCase();
name = name.replace(/ /g, "-");
name = name.split("").filter(function (el) {
return chars.indexOf(el) != -1;
}).join("");
name = name.replace(/\s+/g, "-");
name = name.replace(/[^-a-z0-9]/g, "");
if (!name) {
// Our input had no valid characters - use a random name
var cl = chars.length - 1;
for (var i = 0; i < 8; ++i)
name += chars.charAt(Math.round(Math.random() * cl));
}
// Use a random name if our input had no valid characters.
if (name.length < minLength)
name = Math.random().toString(36).replace(/^.*\./, '');
if (name.length > maxLength)
name = name.substring(0, maxLength);
return name;
// Force max length.
return name.substring(0, maxLength);
}
/**

Просмотреть файл

@ -42,6 +42,11 @@
#
# ***** END LICENSE BLOCK *****
<!DOCTYPE bindings [
<!ENTITY % actionsDTD SYSTEM "chrome://global/locale/actions.dtd">
%actionsDTD;
]>
<bindings id="autocompleteBindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:html="http://www.w3.org/1999/xhtml"
@ -253,10 +258,21 @@
<!-- =================== PUBLIC MEMBERS =================== -->
<property name="value"
onget="return this.inputField.value;">
<property name="value">
<getter><![CDATA[
if (typeof this.onBeforeValueGet == "function") {
var result = this.onBeforeValueGet();
if (result)
return result.value;
}
return this.inputField.value;
]]></getter>
<setter><![CDATA[
this.mIgnoreInput = true;
if (typeof this.onBeforeValueSet == "function")
val = this.onBeforeValueSet(val);
this.inputField.value = val;
this.mIgnoreInput = false;
var event = document.createEvent('Events');
@ -516,11 +532,23 @@
]]></body>
</method>
<method name="resetActionType">
<body><![CDATA[
if (this.mIgnoreInput)
return;
this.removeAttribute("actiontype");
]]></body>
</method>
</implementation>
<handlers>
<handler event="input"
action="if (!this.mIgnoreInput &amp;&amp; this.mController.input == this) this.mController.handleText(true);"/>
<handler event="input"><![CDATA[
if (!this.mIgnoreInput && this.mController.input == this) {
this.mController.handleText(true);
}
this.resetActionType();
]]></handler>
<handler event="keypress" phase="capturing"
action="return this.onKeyPress(event);"/>
@ -1135,7 +1163,7 @@
<binding id="autocomplete-richlistitem" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
<content>
<xul:hbox align="center">
<xul:hbox align="center" class="ac-title-box">
<xul:image xbl:inherits="src=image" class="ac-site-icon"/>
<xul:hbox anonid="title-box" class="ac-title" flex="1"
onunderflow="_doUnderflow('_title');">
@ -1152,6 +1180,7 @@
</xul:hbox>
<xul:hbox align="center" class="ac-url-box">
<xul:spacer class="ac-site-icon"/>
<xul:image class="ac-action-icon"/>
<xul:hbox anonid="url-box" class="ac-url" flex="1"
onunderflow="_doUnderflow('_url');">
<xul:description anonid="url" class="ac-normal-text ac-url-text" xbl:inherits="selected"/>
@ -1325,12 +1354,19 @@
<method name="_setUpDescription">
<parameter name="aDescriptionElement"/>
<parameter name="aText"/>
<parameter name="aNoEmphasis"/>
<body>
<![CDATA[
// Get rid of all previous text
while (aDescriptionElement.hasChildNodes())
aDescriptionElement.removeChild(aDescriptionElement.firstChild);
// If aNoEmphasis is specified, don't add any emphasis
if (aNoEmphasis) {
aDescriptionElement.appendChild(document.createTextNode(aText));
return;
}
// Get the indices that separate match and non-match text
let search = this.getAttribute("text");
let tokens = this._getSearchTokens(search);
@ -1372,6 +1408,10 @@
var title = this.getAttribute("title");
var type = this.getAttribute("type");
this.removeAttribute("actiontype");
var setupUrl = true;
// If we have a tag match, show the tags and icon
if (type == "tag") {
// Configure the extra box for tags display
@ -1413,6 +1453,15 @@
// Don't emphasize keyword searches in the title or url
this.setAttribute("text", "");
} else if (type == "action") {
let [,action, param] = url.match(/^moz-action:([^,]+),(.*)$/);
this.setAttribute("actiontype", action);
url = param;
this._extraBox.hidden = true;
this._titleBox.flex = 1;
let desc = "]]>&action.switchToTab.label;<![CDATA[";
this._setUpDescription(this._url, desc, true);
setupUrl = false;
} else {
// Hide the title's extra box if we don't need extra stuff
this._extraBox.hidden = true;
@ -1429,7 +1478,8 @@
// Emphasize the matching search terms for the description
this._setUpDescription(this._title, title);
this._setUpDescription(this._url, url);
if (setupUrl)
this._setUpDescription(this._url, url);
// Set up overflow on a timeout because the contents of the box
// might not have a width yet even though we just changed them

Просмотреть файл

@ -623,6 +623,9 @@
<field name="mIconURL">null</field>
<!-- This is managed by the tabbrowser -->
<field name="lastURI">null</field>
<field name="mDestroyed">false</field>
<constructor>
@ -699,6 +702,8 @@
// The feeds cache can keep the document inside this browser alive.
this.feeds = null;
this.lastURI = null;
this.removeEventListener("pageshow", this.onPageShow, true);
this.removeEventListener("pagehide", this.onPageHide, true);
this.removeEventListener("DOMPopupBlocked", this.onPopupBlocked, true);

Просмотреть файл

@ -0,0 +1 @@
<!ENTITY action.switchToTab.label "Switch to tab">

Просмотреть файл

@ -6,6 +6,7 @@
locale/@AB_CD@/global/aboutAbout.dtd (%chrome/global/aboutAbout.dtd)
locale/@AB_CD@/global/aboutRights.dtd (%chrome/global/aboutRights.dtd)
locale/@AB_CD@/global/aboutRights.properties (%chrome/global/aboutRights.properties)
locale/@AB_CD@/global/actions.dtd (%chrome/global/actions.dtd)
locale/@AB_CD@/global/appPicker.dtd (%chrome/global/appPicker.dtd)
locale/@AB_CD@/global/brand.dtd (generic/chrome/global/brand.dtd)
+ locale/@AB_CD@/global/browser.properties (%chrome/global/browser.properties)