зеркало из https://github.com/mozilla/gecko-dev.git
Merge
This commit is contained in:
Коммит
60fc2a5c5e
|
@ -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:
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 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
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 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
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 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(¶mCopy, 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 && 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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче