Merge mozilla-central into birch
|
@ -38,11 +38,9 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "mozilla/Util.h"
|
||||
|
||||
#include "nsAccessible.h"
|
||||
#include "nsAccessibleWrap.h"
|
||||
|
||||
#include "Accessible-inl.h"
|
||||
#include "InterfaceInitFuncs.h"
|
||||
#include "nsAccUtils.h"
|
||||
#include "nsApplicationAccessibleWrap.h"
|
||||
|
@ -60,6 +58,7 @@
|
|||
#include "Relation.h"
|
||||
#include "States.h"
|
||||
|
||||
#include "mozilla/Util.h"
|
||||
#include "nsXPCOMStrings.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
|
||||
#include "InterfaceInitFuncs.h"
|
||||
|
||||
#include "Accessible-inl.h"
|
||||
#include "nsMai.h"
|
||||
#include "Role.h"
|
||||
|
||||
|
|
|
@ -23,11 +23,6 @@ var EXPORTED_SYMBOLS = ['VisualPresenter',
|
|||
function Presenter() {}
|
||||
|
||||
Presenter.prototype = {
|
||||
/**
|
||||
* The padding in pixels between the object and the highlight border.
|
||||
*/
|
||||
BORDER_PADDING: 2,
|
||||
|
||||
/**
|
||||
* Attach function for presenter.
|
||||
* @param {ChromeWindow} aWindow Chrome window the presenter could use.
|
||||
|
@ -96,6 +91,11 @@ function VisualPresenter() {}
|
|||
|
||||
VisualPresenter.prototype = new Presenter();
|
||||
|
||||
/**
|
||||
* The padding in pixels between the object and the highlight border.
|
||||
*/
|
||||
VisualPresenter.prototype.BORDER_PADDING = 2;
|
||||
|
||||
VisualPresenter.prototype.attach = function(aWindow) {
|
||||
this.chromeWin = aWindow;
|
||||
|
||||
|
@ -251,7 +251,7 @@ AndroidPresenter.prototype.tabSelected = function(aObject) {
|
|||
context.push(parent);
|
||||
context.reverse();
|
||||
|
||||
this.pivotChanged(vcDoc.virtualCursor.position, context);
|
||||
this.pivotChanged(vcDoc.virtualCursor.position || aObject, context);
|
||||
};
|
||||
|
||||
AndroidPresenter.prototype.sendMessageToJava = function(aMessage) {
|
||||
|
|
|
@ -26,8 +26,8 @@
|
|||
function doTest()
|
||||
{
|
||||
testKeyboardShortcut("input1", "");
|
||||
testKeyboardShortcut("input2", MAC ? "⌃b" : "Alt+Shift+b");
|
||||
testKeyboardShortcut("link", MAC ? "⌃l" : "Alt+Shift+l");
|
||||
testKeyboardShortcut("input2", MAC ? "⌃%b" : "Alt+Shift+b");
|
||||
testKeyboardShortcut("link", MAC ? "⌃%l" : "Alt+Shift+l");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
|
|
@ -237,8 +237,7 @@ const kSansSerifFontFamily =
|
|||
const kSerifFontFamily =
|
||||
function(aFontFamily) { return aFontFamily != "serif"; }
|
||||
|
||||
const kCursiveFontFamily = WIN ? "Comic Sans MS" :
|
||||
(LINUX ? "DejaVu Serif" : "MacFont");
|
||||
const kCursiveFontFamily = LINUX ? "DejaVu Serif" : "Comic Sans MS";
|
||||
|
||||
/**
|
||||
* Return used font from the given computed style.
|
||||
|
|
|
@ -210,7 +210,7 @@
|
|||
aria-labelledby="l1 l2"
|
||||
alt="Mozilla logo"
|
||||
title="This is a logo"
|
||||
src="moz.png"/>
|
||||
src="../moz.png"/>
|
||||
</markup>
|
||||
|
||||
<markup ref="html:img" ruleset="htmlimageemptyalt">
|
||||
|
@ -221,7 +221,7 @@
|
|||
aria-labelledby="l1 l2"
|
||||
title="This is a logo"
|
||||
alt=""
|
||||
src="moz.png"/>
|
||||
src="../moz.png"/>
|
||||
</markup>
|
||||
|
||||
<markup ref="html:table/html:tr/html:td" ruleset="htmlelm"
|
||||
|
|
|
@ -40,6 +40,12 @@ probes/Makefile
|
|||
extensions/Makefile
|
||||
"
|
||||
|
||||
if [ "$MOZ_WEBAPP_RUNTIME" ]; then
|
||||
add_makefiles "
|
||||
webapprt/Makefile
|
||||
"
|
||||
fi
|
||||
|
||||
if [ ! "$LIBXUL_SDK" ]; then
|
||||
if [ "$STLPORT_SOURCES" ]; then
|
||||
add_makefiles "
|
||||
|
|
|
@ -349,6 +349,12 @@ pref("browser.download.manager.quitBehavior", 0);
|
|||
pref("browser.download.manager.scanWhenDone", true);
|
||||
pref("browser.download.manager.resumeOnWakeDelay", 10000);
|
||||
|
||||
// This allows disabling the Downloads Panel in favor of the old interface.
|
||||
pref("browser.download.useToolkitUI", false);
|
||||
|
||||
// This controls retention behavior in the Downloads Panel only.
|
||||
pref("browser.download.panel.removeFinishedDownloads", false);
|
||||
|
||||
// search engines URL
|
||||
pref("browser.search.searchEnginesURL", "https://addons.mozilla.org/%LOCALE%/firefox/search-engines/");
|
||||
|
||||
|
|
|
@ -1391,6 +1391,8 @@ function BrowserStartup() {
|
|||
|
||||
gPrivateBrowsingUI.init();
|
||||
|
||||
DownloadsButton.initializePlaceholder();
|
||||
|
||||
retrieveToolbarIconsizesFromTheme();
|
||||
|
||||
gDelayedStartupTimeoutId = setTimeout(delayedStartup, 0, isLoadingBlank, mustLoadSidebar);
|
||||
|
@ -1640,6 +1642,11 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
|||
#endif
|
||||
}, 10000);
|
||||
|
||||
// The object handling the downloads indicator is also initialized here in the
|
||||
// delayed startup function, but the actual indicator element is not loaded
|
||||
// unless there are downloads to be displayed.
|
||||
DownloadsButton.initializeIndicator();
|
||||
|
||||
#ifndef XP_MACOSX
|
||||
updateEditUIVisibility();
|
||||
let placesContext = document.getElementById("placesContext");
|
||||
|
@ -3722,6 +3729,7 @@ function BrowserCustomizeToolbar()
|
|||
|
||||
PlacesToolbarHelper.customizeStart();
|
||||
BookmarksMenuButton.customizeStart();
|
||||
DownloadsButton.customizeStart();
|
||||
|
||||
TabsInTitlebar.allowedBy("customizing-toolbars", false);
|
||||
|
||||
|
@ -3788,6 +3796,7 @@ function BrowserToolboxCustomizeDone(aToolboxChanged) {
|
|||
|
||||
PlacesToolbarHelper.customizeDone();
|
||||
BookmarksMenuButton.customizeDone();
|
||||
DownloadsButton.customizeDone();
|
||||
|
||||
// The url bar splitter state is dependent on whether stop/reload
|
||||
// and the location bar are combined, so we need this ordering
|
||||
|
|
|
@ -855,6 +855,9 @@
|
|||
label="&printButton.label;" command="cmd_print"
|
||||
tooltiptext="&printButton.tooltip;"/>
|
||||
|
||||
<!-- This is a placeholder for the Downloads Indicator. It is visible
|
||||
only during the customization of the toolbar or in the palette, and
|
||||
is replaced when customization is done. -->
|
||||
<toolbarbutton id="downloads-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
|
||||
observes="Tools:Downloads"
|
||||
ondrop="DownloadsButtonDNDObserver.onDrop(event)"
|
||||
|
|
|
@ -41,5 +41,7 @@
|
|||
<script type="application/javascript" src="chrome://global/content/viewZoomOverlay.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/places/browserPlacesViews.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/browser.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/downloads/downloads.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/downloads/indicator.js"/>
|
||||
<script type="application/javascript" src="chrome://global/content/inlineSpellCheckUI.js"/>
|
||||
<script type="application/javascript" src="chrome://global/content/viewSourceUtils.js"/>
|
||||
|
|
|
@ -51,6 +51,10 @@ ifdef MOZ_SERVICES_SYNC
|
|||
tier_app_dirs += services
|
||||
endif
|
||||
|
||||
ifdef MOZ_WEBAPP_RUNTIME
|
||||
tier_app_dirs += webapprt
|
||||
endif
|
||||
|
||||
tier_app_dirs += browser
|
||||
# Never add other tier_app_dirs after browser. They won't get packaged
|
||||
# properly on mac.
|
||||
|
|
|
@ -24,8 +24,22 @@ category command-line-handler x-default @mozilla.org/browser/final-clh;1 applica
|
|||
category command-line-validator b-browser @mozilla.org/browser/clh;1 application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
|
||||
|
||||
# nsBrowserGlue.js
|
||||
|
||||
# WebappRT doesn't need these instructions, and they don't necessarily work
|
||||
# with it, but it does use a GRE directory that the GRE shares with Firefox,
|
||||
# so in order to prevent the instructions from being processed for WebappRT,
|
||||
# we need to restrict them to the applications that depend on them, i.e.:
|
||||
#
|
||||
# b2g: {3c2e2abc-06d4-11e1-ac3b-374f68613e61}
|
||||
# browser: {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
|
||||
# mobile/android: {aa3c5121-dab2-40e2-81ca-7ea25febc110}
|
||||
# mobile/xul: {a23983c0-fd0e-11dc-95ff-0800200c9a66}
|
||||
#
|
||||
# In theory we should do this for all these instructions, but in practice it is
|
||||
# sufficient to do it for the app-startup one, and the file is simpler that way.
|
||||
|
||||
component {eab9012e-5f74-4cbc-b2b5-a590235513cc} nsBrowserGlue.js
|
||||
contract @mozilla.org/browser/browserglue;1 {eab9012e-5f74-4cbc-b2b5-a590235513cc}
|
||||
category app-startup nsBrowserGlue service,@mozilla.org/browser/browserglue;1
|
||||
category app-startup nsBrowserGlue service,@mozilla.org/browser/browserglue;1 application={3c2e2abc-06d4-11e1-ac3b-374f68613e61} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} application={aa3c5121-dab2-40e2-81ca-7ea25febc110} application={a23983c0-fd0e-11dc-95ff-0800200c9a66}
|
||||
component {d8903bf6-68d5-4e97-bcd1-e4d3012f721a} nsBrowserGlue.js
|
||||
contract @mozilla.org/content-permission/prompt;1 {d8903bf6-68d5-4e97-bcd1-e4d3012f721a}
|
||||
|
|
|
@ -62,6 +62,7 @@ PARALLEL_DIRS = \
|
|||
about \
|
||||
certerror \
|
||||
dirprovider \
|
||||
downloads \
|
||||
feeds \
|
||||
places \
|
||||
preferences \
|
||||
|
|
|
@ -36,12 +36,7 @@
|
|||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "@mozilla.org/profile/migrator;1?app=browser&type="
|
||||
|
||||
#ifdef XP_WIN
|
||||
#define NS_WINIEPROFILEMIGRATOR_CID \
|
||||
{ 0xbc15c73d, 0xc05b, 0x497b, { 0xa3, 0x73, 0x4b, 0xae, 0x6c, 0x17, 0x86, 0x31 } }
|
||||
|
||||
#define NS_WINIEHISTORYENUMERATOR_CID \
|
||||
{ 0x93480624, 0x806e, 0x4756, { 0xb7, 0xcb, 0x0f, 0xb7, 0xdd, 0x74, 0x6a, 0x8f } }
|
||||
|
||||
|
@ -49,11 +44,6 @@
|
|||
"@mozilla.org/profile/migrator/iehistoryenumerator;1"
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#define NS_SAFARIPROFILEMIGRATOR_CID \
|
||||
{ 0x29e3b139, 0xad19, 0x44f3, { 0xb2, 0xc2, 0xe9, 0xf1, 0x3b, 0xa2, 0xbb, 0xc6 } }
|
||||
#endif
|
||||
|
||||
#define NS_SHELLSERVICE_CID \
|
||||
{ 0x63c7b9f4, 0xcc8, 0x43f8, { 0xb6, 0x66, 0xa, 0x66, 0x16, 0x55, 0xcb, 0x73 } }
|
||||
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
#endif
|
||||
|
||||
#if defined(XP_WIN) && !defined(__MINGW32__)
|
||||
#include "nsIEProfileMigrator.h"
|
||||
#include "nsIEHistoryEnumerator.h"
|
||||
#endif
|
||||
|
||||
|
@ -76,7 +75,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGNOMEShellService, Init)
|
|||
#endif
|
||||
|
||||
#if defined(XP_WIN) && !defined(__MINGW32__)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsIEProfileMigrator)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsIEHistoryEnumerator)
|
||||
#endif
|
||||
|
||||
|
@ -93,7 +91,6 @@ NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
|
|||
NS_DEFINE_NAMED_CID(NS_FEEDSNIFFER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_BROWSER_ABOUT_REDIRECTOR_CID);
|
||||
#if defined(XP_WIN) && !defined(__MINGW32__)
|
||||
NS_DEFINE_NAMED_CID(NS_WINIEPROFILEMIGRATOR_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_WINIEHISTORYENUMERATOR_CID);
|
||||
#elif defined(XP_MACOSX)
|
||||
NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
|
||||
|
@ -110,7 +107,6 @@ static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
|
|||
{ &kNS_FEEDSNIFFER_CID, false, NULL, nsFeedSnifferConstructor },
|
||||
{ &kNS_BROWSER_ABOUT_REDIRECTOR_CID, false, NULL, AboutRedirector::Create },
|
||||
#if defined(XP_WIN) && !defined(__MINGW32__)
|
||||
{ &kNS_WINIEPROFILEMIGRATOR_CID, false, NULL, nsIEProfileMigratorConstructor },
|
||||
{ &kNS_WINIEHISTORYENUMERATOR_CID, false, NULL, nsIEHistoryEnumeratorConstructor },
|
||||
#elif defined(XP_MACOSX)
|
||||
{ &kNS_SHELLSERVICE_CID, false, NULL, nsMacShellServiceConstructor },
|
||||
|
@ -144,7 +140,6 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
|
|||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "newtab", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "permissions", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
#if defined(XP_WIN) && !defined(__MINGW32__)
|
||||
{ NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "ie", &kNS_WINIEPROFILEMIGRATOR_CID },
|
||||
{ NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID },
|
||||
#elif defined(XP_MACOSX)
|
||||
{ NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = src
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += test
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0"?>
|
||||
# -*- Mode: HTML; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
# vim: set ts=2 et sw=2 tw=80:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
<!DOCTYPE bindings SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
|
||||
|
||||
<bindings id="downloadBindings"
|
||||
xmlns="http://www.mozilla.org/xbl"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:xbl="http://www.mozilla.org/xbl">
|
||||
|
||||
<binding id="download"
|
||||
extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
|
||||
<resources>
|
||||
<stylesheet src="chrome://browser/skin/downloads/downloads.css"/>
|
||||
</resources>
|
||||
<content orient="horizontal">
|
||||
<xul:hbox class="downloadInfo"
|
||||
align="center"
|
||||
flex="1"
|
||||
onclick="DownloadsView.onDownloadClick(event);">
|
||||
<xul:vbox pack="center">
|
||||
<xul:image class="downloadTypeIcon"
|
||||
validate="always"
|
||||
xbl:inherits="src=image"/>
|
||||
<xul:image class="downloadTypeIcon blockedIcon"/>
|
||||
</xul:vbox>
|
||||
<xul:vbox pack="center"
|
||||
flex="1">
|
||||
<xul:description class="downloadTarget"
|
||||
crop="center"
|
||||
xbl:inherits="value=target,tooltiptext=target"/>
|
||||
<xul:progressmeter anonid="progressmeter"
|
||||
class="downloadProgress"
|
||||
min="0"
|
||||
max="100"
|
||||
xbl:inherits="mode=progressmode,value=progress"/>
|
||||
<xul:description class="downloadDetails"
|
||||
crop="end"
|
||||
xbl:inherits="value=status,tooltiptext=statusTip"/>
|
||||
</xul:vbox>
|
||||
</xul:hbox>
|
||||
<xul:hbox class="downloadButtonContainer"
|
||||
align="center">
|
||||
<xul:button class="downloadButton downloadCancel"
|
||||
tooltiptext="&cmd.cancel.label;"
|
||||
oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_cancel');"/>
|
||||
<xul:button class="downloadButton downloadRetry"
|
||||
tooltiptext="&cmd.retry.label;"
|
||||
oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_retry');"/>
|
||||
<xul:button class="downloadButton downloadShow"
|
||||
tooltiptext="&cmd.show.label;"
|
||||
oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_show');"/>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
</binding>
|
||||
</bindings>
|
|
@ -0,0 +1,90 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*** Download items ***/
|
||||
|
||||
richlistitem[type="download"] {
|
||||
-moz-binding: url('chrome://browser/content/downloads/download.xml#download');
|
||||
}
|
||||
|
||||
richlistitem[type="download"]:not([selected]) button {
|
||||
/* Only focus buttons in the selected item. */
|
||||
-moz-user-focus: none;
|
||||
}
|
||||
|
||||
/*** Visibility of controls inside download items ***/
|
||||
|
||||
.download-state:-moz-any( [state="6"], /* Blocked (parental) */
|
||||
[state="8"], /* Blocked (dirty) */
|
||||
[state="9"]) /* Blocked (policy) */
|
||||
.downloadTypeIcon:not(.blockedIcon),
|
||||
|
||||
.download-state:not(:-moz-any([state="6"], /* Blocked (parental) */
|
||||
[state="8"], /* Blocked (dirty) */
|
||||
[state="9"]) /* Blocked (policy) */)
|
||||
.downloadTypeIcon.blockedIcon,
|
||||
|
||||
.download-state:not(:-moz-any([state="-1"],/* Starting (initial) */
|
||||
[state="5"], /* Starting (queued) */
|
||||
[state="0"], /* Downloading */
|
||||
[state="4"], /* Paused */
|
||||
[state="7"]) /* Scanning */)
|
||||
.downloadProgress,
|
||||
|
||||
.download-state:not( [state="0"] /* Downloading */)
|
||||
.downloadPauseMenuItem,
|
||||
|
||||
.download-state:not( [state="4"] /* Paused */)
|
||||
.downloadResumeMenuItem,
|
||||
|
||||
.download-state:not(:-moz-any([state="-1"],/* Starting (initial) */
|
||||
[state="5"], /* Starting (queued) */
|
||||
[state="0"], /* Downloading */
|
||||
[state="4"]) /* Paused */)
|
||||
.downloadCancel,
|
||||
|
||||
.download-state:not(:-moz-any([state="2"], /* Failed */
|
||||
[state="4"]) /* Paused */)
|
||||
.downloadCancelMenuItem,
|
||||
|
||||
.download-state:not(:-moz-any([state="1"], /* Finished */
|
||||
[state="3"], /* Canceled */
|
||||
[state="6"], /* Blocked (parental) */
|
||||
[state="8"], /* Blocked (dirty) */
|
||||
[state="9"]) /* Blocked (policy) */)
|
||||
.downloadRemoveFromListMenuItem,
|
||||
|
||||
.download-state:not(:-moz-any([state="2"], /* Failed */
|
||||
[state="3"]) /* Canceled */)
|
||||
.downloadRetry,
|
||||
|
||||
.download-state:not( [state="1"] /* Finished */)
|
||||
.downloadShow,
|
||||
|
||||
.download-state:not(:-moz-any([state="-1"],/* Starting (initial) */
|
||||
[state="5"], /* Starting (queued) */
|
||||
[state="0"], /* Downloading */
|
||||
[state="4"]) /* Paused */)
|
||||
.downloadShowMenuItem,
|
||||
|
||||
.download-state[state="7"] .downloadCommandsSeparator
|
||||
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*** Visibility of controls inside the downloads indicator ***/
|
||||
|
||||
#downloads-indicator:-moz-any([progress],
|
||||
[counter],
|
||||
[paused]) #downloads-indicator-icon,
|
||||
|
||||
#downloads-indicator:not(:-moz-any([progress],
|
||||
[counter],
|
||||
[paused]))
|
||||
#downloads-indicator-progress-area
|
||||
|
||||
{
|
||||
visibility: hidden;
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
<?xml version="1.0"?>
|
||||
# -*- Mode: HTML; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
# vim: set ts=2 et sw=2 tw=80:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/content/downloads/downloads.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/downloads/downloads.css"?>
|
||||
|
||||
<!DOCTYPE overlay SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
|
||||
|
||||
<overlay xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
id="downloadsOverlay">
|
||||
|
||||
<commandset>
|
||||
<command id="downloadsCmd_doDefault"
|
||||
oncommand="goDoCommand('downloadsCmd_doDefault')"/>
|
||||
<command id="downloadsCmd_pauseResume"
|
||||
oncommand="goDoCommand('downloadsCmd_pauseResume')"/>
|
||||
<command id="downloadsCmd_cancel"
|
||||
oncommand="goDoCommand('downloadsCmd_cancel')"/>
|
||||
<command id="downloadsCmd_open"
|
||||
oncommand="goDoCommand('downloadsCmd_open')"/>
|
||||
<command id="downloadsCmd_show"
|
||||
oncommand="goDoCommand('downloadsCmd_show')"/>
|
||||
<command id="downloadsCmd_retry"
|
||||
oncommand="goDoCommand('downloadsCmd_retry')"/>
|
||||
<command id="downloadsCmd_openReferrer"
|
||||
oncommand="goDoCommand('downloadsCmd_openReferrer')"/>
|
||||
<command id="downloadsCmd_copyLocation"
|
||||
oncommand="goDoCommand('downloadsCmd_copyLocation')"/>
|
||||
<command id="downloadsCmd_clearList"
|
||||
oncommand="goDoCommand('downloadsCmd_clearList')"/>
|
||||
</commandset>
|
||||
|
||||
<popupset>
|
||||
<!-- The panel has level="top" to ensure that it is never hidden by the
|
||||
taskbar on Windows. See bug 672365. For accessibility to screen
|
||||
readers, we use a label on the panel instead of the anchor because the
|
||||
panel can also be displayed without an anchor. -->
|
||||
<panel id="downloadsPanel"
|
||||
aria-label="&downloads.title;"
|
||||
role="group"
|
||||
type="arrow"
|
||||
orient="vertical"
|
||||
level="top"
|
||||
onpopupshown="DownloadsPanel.onPopupShown(event);"
|
||||
onpopuphidden="DownloadsPanel.onPopupHidden(event);">
|
||||
<!-- The following popup menu should be a child of the panel element,
|
||||
otherwise flickering may occur when the cursor is moved over the area
|
||||
of a disabled menu item that overlaps the panel. See bug 492960. -->
|
||||
<menupopup id="downloadsContextMenu"
|
||||
class="download-state">
|
||||
<menuitem command="downloadsCmd_pauseResume"
|
||||
class="downloadPauseMenuItem"
|
||||
label="&cmd.pause.label;"
|
||||
accesskey="&cmd.pause.accesskey;"/>
|
||||
<menuitem command="downloadsCmd_pauseResume"
|
||||
class="downloadResumeMenuItem"
|
||||
label="&cmd.resume.label;"
|
||||
accesskey="&cmd.resume.accesskey;"/>
|
||||
<menuitem command="downloadsCmd_cancel"
|
||||
class="downloadCancelMenuItem"
|
||||
label="&cmd.cancel.label;"
|
||||
accesskey="&cmd.cancel.accesskey;"/>
|
||||
<menuitem command="cmd_delete"
|
||||
class="downloadRemoveFromListMenuItem"
|
||||
label="&cmd.removeFromList.label;"
|
||||
accesskey="&cmd.removeFromList.accesskey;"/>
|
||||
<menuitem command="downloadsCmd_show"
|
||||
class="downloadShowMenuItem"
|
||||
#ifdef XP_MACOSX
|
||||
label="&cmd.showMac.label;"
|
||||
accesskey="&cmd.showMac.accesskey;"
|
||||
#else
|
||||
label="&cmd.show.label;"
|
||||
accesskey="&cmd.show.accesskey;"
|
||||
#endif
|
||||
/>
|
||||
|
||||
<menuseparator class="downloadCommandsSeparator"/>
|
||||
|
||||
<menuitem command="downloadsCmd_openReferrer"
|
||||
label="&cmd.goToDownloadPage.label;"
|
||||
accesskey="&cmd.goToDownloadPage.accesskey;"/>
|
||||
<menuitem command="downloadsCmd_copyLocation"
|
||||
label="&cmd.copyDownloadLink.label;"
|
||||
accesskey="&cmd.copyDownloadLink.accesskey;"/>
|
||||
|
||||
<menuseparator/>
|
||||
|
||||
<menuitem command="downloadsCmd_clearList"
|
||||
label="&cmd.clearList.label;"
|
||||
accesskey="&cmd.clearList.accesskey;"/>
|
||||
</menupopup>
|
||||
|
||||
<richlistbox id="downloadsListBox"
|
||||
class="plain"
|
||||
flex="1"
|
||||
context="downloadsContextMenu"
|
||||
onkeypress="DownloadsView.onDownloadKeyPress(event);"
|
||||
oncontextmenu="DownloadsView.onDownloadContextMenu(event);"
|
||||
ondragstart="DownloadsView.onDownloadDragStart(event);"/>
|
||||
|
||||
<button id="downloadsHistory"
|
||||
class="plain"
|
||||
label="&downloadshistory.label;"
|
||||
accesskey="&downloadshistory.accesskey;"
|
||||
oncommand="DownloadsPanel.showDownloadsHistory();"/>
|
||||
</panel>
|
||||
</popupset>
|
||||
</overlay>
|
|
@ -0,0 +1,591 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Handles the indicator that displays the progress of ongoing downloads, which
|
||||
* is also used as the anchor for the downloads panel.
|
||||
*
|
||||
* This module includes the following constructors and global objects:
|
||||
*
|
||||
* DownloadsButton
|
||||
* Main entry point for the downloads indicator. Depending on how the toolbars
|
||||
* have been customized, this object determines if we should show a fully
|
||||
* functional indicator, a placeholder used during customization and in the
|
||||
* customization palette, or a neutral view as a temporary anchor for the
|
||||
* downloads panel.
|
||||
*
|
||||
* DownloadsIndicatorView
|
||||
* Builds and updates the actual downloads status widget, responding to changes
|
||||
* in the global status data, or provides a neutral view if the indicator is
|
||||
* removed from the toolbars and only used as a temporary anchor. In addition,
|
||||
* handles the user interaction events raised by the widget.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// DownloadsButton
|
||||
|
||||
/**
|
||||
* Main entry point for the downloads indicator. Depending on how the toolbars
|
||||
* have been customized, this object determines if we should show a fully
|
||||
* functional indicator, a placeholder used during customization and in the
|
||||
* customization palette, or a neutral view as a temporary anchor for the
|
||||
* downloads panel.
|
||||
*/
|
||||
const DownloadsButton = {
|
||||
/**
|
||||
* Location of the indicator overlay.
|
||||
*/
|
||||
get kIndicatorOverlay()
|
||||
"chrome://browser/content/downloads/indicatorOverlay.xul",
|
||||
|
||||
/**
|
||||
* Returns a reference to the downloads button position placeholder, or null
|
||||
* if not available because it has been removed from the toolbars.
|
||||
*/
|
||||
get _placeholder()
|
||||
{
|
||||
return document.getElementById("downloads-button");
|
||||
},
|
||||
|
||||
/**
|
||||
* This function is called synchronously at window initialization. It only
|
||||
* sets the visibility of user interface elements to avoid flickering.
|
||||
*
|
||||
* NOTE: To keep startup time to a minimum, this function should not perform
|
||||
* any expensive operations or input/output, and should not cause the
|
||||
* Download Manager service to start.
|
||||
*/
|
||||
initializePlaceholder: function DB_initializePlaceholder()
|
||||
{
|
||||
// Exit now if the feature is disabled. To improve startup time, we don't
|
||||
// load the DownloadsCommon module yet, but check the preference directly.
|
||||
if (gPrefService.getBoolPref("browser.download.useToolkitUI")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We must hide the placeholder used for toolbar customization, unless it
|
||||
// has been removed from the toolbars and is now located in the palette.
|
||||
let placeholder = this._placeholder;
|
||||
if (placeholder) {
|
||||
placeholder.collapsed = true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This function is called asynchronously just after window initialization.
|
||||
*
|
||||
* NOTE: This function should limit the input/output it performs to improve
|
||||
* startup time, and in particular should not cause the Download Manager
|
||||
* service to start.
|
||||
*/
|
||||
initializeIndicator: function DB_initializeIndicator()
|
||||
{
|
||||
this._update();
|
||||
},
|
||||
|
||||
/**
|
||||
* Indicates whether toolbar customization is in progress.
|
||||
*/
|
||||
_customizing: false,
|
||||
|
||||
/**
|
||||
* This function is called when toolbar customization starts.
|
||||
*
|
||||
* During customization, we never show the actual download progress indication
|
||||
* or the event notifications, but we show a neutral placeholder. The neutral
|
||||
* placeholder is an ordinary button defined in the browser window that can be
|
||||
* moved freely between the toolbars and the customization palette.
|
||||
*/
|
||||
customizeStart: function DB_customizeStart()
|
||||
{
|
||||
// Hide the indicator and prevent it to be displayed as a temporary anchor
|
||||
// during customization, even if requested using the getAnchor method.
|
||||
this._customizing = true;
|
||||
this._anchorRequested = false;
|
||||
|
||||
let indicator = DownloadsIndicatorView.indicator;
|
||||
if (indicator) {
|
||||
indicator.collapsed = true;
|
||||
}
|
||||
|
||||
let placeholder = this._placeholder;
|
||||
if (placeholder) {
|
||||
placeholder.collapsed = false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This function is called when toolbar customization ends.
|
||||
*/
|
||||
customizeDone: function DB_customizeDone()
|
||||
{
|
||||
this._customizing = false;
|
||||
this._update();
|
||||
},
|
||||
|
||||
/**
|
||||
* This function is called during initialization or when toolbar customization
|
||||
* ends. It determines if we should enable or disable the object that keeps
|
||||
* the indicator updated, and ensures that the placeholder is hidden unless it
|
||||
* has been moved to the customization palette.
|
||||
*
|
||||
* NOTE: This function is also called on startup, thus it should limit the
|
||||
* input/output it performs, and in particular should not cause the
|
||||
* Download Manager service to start.
|
||||
*/
|
||||
_update: function DB_update() {
|
||||
this._updatePositionInternal();
|
||||
|
||||
let placeholder = this._placeholder;
|
||||
if (!DownloadsCommon.useToolkitUI) {
|
||||
DownloadsIndicatorView.ensureInitialized();
|
||||
if (placeholder) {
|
||||
placeholder.collapsed = true;
|
||||
}
|
||||
} else {
|
||||
DownloadsIndicatorView.ensureTerminated();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines the position where the indicator should appear, and moves its
|
||||
* associated element to the new position. This does not happen if the
|
||||
* indicator is currently being used as the anchor for the panel, to ensure
|
||||
* that the panel doesn't flicker because we move the DOM element to which
|
||||
* it's anchored.
|
||||
*/
|
||||
updatePosition: function DB_updatePosition()
|
||||
{
|
||||
if (!this._anchorRequested) {
|
||||
this._updatePositionInternal();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines the position where the indicator should appear, and moves its
|
||||
* associated element to the new position.
|
||||
*
|
||||
* @return Anchor element, or null if the indicator is not visible.
|
||||
*/
|
||||
_updatePositionInternal: function DB_updatePositionInternal()
|
||||
{
|
||||
let indicator = DownloadsIndicatorView.indicator;
|
||||
if (!indicator) {
|
||||
// Exit now if the indicator overlay isn't loaded yet.
|
||||
return null;
|
||||
}
|
||||
|
||||
let placeholder = this._placeholder;
|
||||
|
||||
// Firstly, determine if we should always hide the indicator.
|
||||
if (!placeholder && !this._anchorRequested &&
|
||||
!DownloadsIndicatorView.hasDownloads) {
|
||||
indicator.collapsed = true;
|
||||
return null;
|
||||
}
|
||||
indicator.collapsed = false;
|
||||
|
||||
indicator.open = this._anchorRequested;
|
||||
|
||||
// Determine if we should display the indicator in a known position.
|
||||
if (placeholder) {
|
||||
placeholder.parentNode.insertBefore(indicator, placeholder);
|
||||
// Determine if the placeholder is located on a visible toolbar.
|
||||
if (isElementVisible(placeholder.parentNode)) {
|
||||
return DownloadsIndicatorView.indicatorAnchor;
|
||||
}
|
||||
}
|
||||
|
||||
// If not customized, the indicator is normally in the navigation bar.
|
||||
// Always place it in the default position, unless we need an anchor.
|
||||
if (!this._anchorRequested) {
|
||||
this._navBar.appendChild(indicator);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Show the indicator temporarily in the navigation bar, if visible.
|
||||
if (isElementVisible(this._navBar)) {
|
||||
this._navBar.appendChild(indicator);
|
||||
return DownloadsIndicatorView.indicatorAnchor;
|
||||
}
|
||||
|
||||
// Show the indicator temporarily in the tab bar, if visible.
|
||||
if (!this._tabsToolbar.collapsed) {
|
||||
this._tabsToolbar.appendChild(indicator);
|
||||
return DownloadsIndicatorView.indicatorAnchor;
|
||||
}
|
||||
|
||||
// The temporary anchor cannot be shown.
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Indicates whether we should try and show the indicator temporarily as an
|
||||
* anchor for the panel, even if the indicator would be hidden by default.
|
||||
*/
|
||||
_anchorRequested: false,
|
||||
|
||||
/**
|
||||
* Ensures that there is an anchor available for the panel.
|
||||
*
|
||||
* @param aCallback
|
||||
* Called when the anchor is available, passing the element where the
|
||||
* panel should be anchored, or null if an anchor is not available (for
|
||||
* example because both the tab bar and the navigation bar are hidden).
|
||||
*/
|
||||
getAnchor: function DB_getAnchor(aCallback)
|
||||
{
|
||||
// Do not allow anchoring the panel to the element while customizing.
|
||||
if (this._customizing) {
|
||||
aCallback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
function DB_GA_callback() {
|
||||
this._anchorRequested = true;
|
||||
aCallback(this._updatePositionInternal());
|
||||
}
|
||||
|
||||
DownloadsOverlayLoader.ensureOverlayLoaded(this.kIndicatorOverlay,
|
||||
DB_GA_callback.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Allows the temporary anchor to be hidden.
|
||||
*/
|
||||
releaseAnchor: function DB_releaseAnchor()
|
||||
{
|
||||
this._anchorRequested = false;
|
||||
this._updatePositionInternal();
|
||||
},
|
||||
|
||||
get _tabsToolbar()
|
||||
{
|
||||
delete this._tabsToolbar;
|
||||
return this._tabsToolbar = document.getElementById("TabsToolbar");
|
||||
},
|
||||
|
||||
get _navBar()
|
||||
{
|
||||
delete this._navBar;
|
||||
return this._navBar = document.getElementById("nav-bar");
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// DownloadsIndicatorView
|
||||
|
||||
/**
|
||||
* Builds and updates the actual downloads status widget, responding to changes
|
||||
* in the global status data, or provides a neutral view if the indicator is
|
||||
* removed from the toolbars and only used as a temporary anchor. In addition,
|
||||
* handles the user interaction events raised by the widget.
|
||||
*/
|
||||
const DownloadsIndicatorView = {
|
||||
/**
|
||||
* True when the view is connected with the underlying downloads data.
|
||||
*/
|
||||
_initialized: false,
|
||||
|
||||
/**
|
||||
* True when the user interface elements required to display the indicator
|
||||
* have finished loading in the browser window, and can be referenced.
|
||||
*/
|
||||
_operational: false,
|
||||
|
||||
/**
|
||||
* Prepares the downloads indicator to be displayed.
|
||||
*/
|
||||
ensureInitialized: function DIV_ensureInitialized()
|
||||
{
|
||||
if (this._initialized) {
|
||||
return;
|
||||
}
|
||||
this._initialized = true;
|
||||
|
||||
window.addEventListener("unload", this.onWindowUnload, false);
|
||||
DownloadsCommon.indicatorData.addView(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Frees the internal resources related to the indicator.
|
||||
*/
|
||||
ensureTerminated: function DIV_ensureTerminated()
|
||||
{
|
||||
if (!this._initialized) {
|
||||
return;
|
||||
}
|
||||
this._initialized = false;
|
||||
|
||||
window.removeEventListener("unload", this.onWindowUnload, false);
|
||||
DownloadsCommon.indicatorData.removeView(this);
|
||||
|
||||
// Reset the view properties, so that a neutral indicator is displayed if we
|
||||
// are visible only temporarily as an anchor.
|
||||
this.counter = "";
|
||||
this.percentComplete = 0;
|
||||
this.paused = false;
|
||||
this.attention = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensures that the user interface elements required to display the indicator
|
||||
* are loaded, then invokes the given callback.
|
||||
*/
|
||||
_ensureOperational: function DIV_ensureOperational(aCallback)
|
||||
{
|
||||
if (this._operational) {
|
||||
aCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
function DIV_EO_callback() {
|
||||
this._operational = true;
|
||||
|
||||
// If the view is initialized, we need to update the elements now that
|
||||
// they are finally available in the document.
|
||||
if (this._initialized) {
|
||||
DownloadsCommon.indicatorData.refreshView(this);
|
||||
}
|
||||
|
||||
aCallback();
|
||||
}
|
||||
|
||||
DownloadsOverlayLoader.ensureOverlayLoaded(
|
||||
DownloadsButton.kIndicatorOverlay,
|
||||
DIV_EO_callback.bind(this));
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// Direct control functions
|
||||
|
||||
/**
|
||||
* Set while we are waiting for a notification to fade out.
|
||||
*/
|
||||
_notificationTimeout: null,
|
||||
|
||||
/**
|
||||
* If the status indicator is visible in its assigned position, shows for a
|
||||
* brief time a visual notification of a relevant event, like a new download.
|
||||
*/
|
||||
showEventNotification: function DIV_showEventNotification()
|
||||
{
|
||||
if (!this._initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
function DIV_SEN_callback() {
|
||||
if (this._notificationTimeout) {
|
||||
clearTimeout(this._notificationTimeout);
|
||||
}
|
||||
|
||||
let indicator = this.indicator;
|
||||
indicator.setAttribute("notification", "true");
|
||||
this._notificationTimeout = setTimeout(
|
||||
function () indicator.removeAttribute("notification"), 1000);
|
||||
}
|
||||
|
||||
this._ensureOperational(DIV_SEN_callback.bind(this));
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// Callback functions from DownloadsIndicatorData
|
||||
|
||||
/**
|
||||
* Indicates whether the indicator should be shown because there are some
|
||||
* downloads to be displayed.
|
||||
*/
|
||||
set hasDownloads(aValue)
|
||||
{
|
||||
if (this._hasDownloads != aValue) {
|
||||
this._hasDownloads = aValue;
|
||||
|
||||
// If there is at least one download, ensure that the view elements are
|
||||
// loaded before determining the position of the downloads button.
|
||||
if (aValue) {
|
||||
this._ensureOperational(function() DownloadsButton.updatePosition());
|
||||
} else {
|
||||
DownloadsButton.updatePosition();
|
||||
}
|
||||
}
|
||||
return aValue;
|
||||
},
|
||||
get hasDownloads()
|
||||
{
|
||||
return this._hasDownloads;
|
||||
},
|
||||
_hasDownloads: false,
|
||||
|
||||
/**
|
||||
* Status text displayed in the indicator. If this is set to an empty value,
|
||||
* then the small downloads icon is displayed instead of the text.
|
||||
*/
|
||||
set counter(aValue)
|
||||
{
|
||||
if (!this._operational) {
|
||||
return this._counter;
|
||||
}
|
||||
|
||||
if (this._counter !== aValue) {
|
||||
this._counter = aValue;
|
||||
if (this._counter)
|
||||
this.indicator.setAttribute("counter", "true");
|
||||
else
|
||||
this.indicator.removeAttribute("counter");
|
||||
// We have to set the attribute instead of using the property because the
|
||||
// XBL binding isn't applied if the element is invisible for any reason.
|
||||
this._indicatorCounter.setAttribute("value", aValue);
|
||||
}
|
||||
return aValue;
|
||||
},
|
||||
_counter: null,
|
||||
|
||||
/**
|
||||
* Progress indication to display, from 0 to 100, or -1 if unknown. The
|
||||
* progress bar is hidden if the current progress is unknown and no status
|
||||
* text is set in the "counter" property.
|
||||
*/
|
||||
set percentComplete(aValue)
|
||||
{
|
||||
if (!this._operational) {
|
||||
return this._percentComplete;
|
||||
}
|
||||
|
||||
if (this._percentComplete !== aValue) {
|
||||
this._percentComplete = aValue;
|
||||
if (this._percentComplete >= 0)
|
||||
this.indicator.setAttribute("progress", "true");
|
||||
else
|
||||
this.indicator.removeAttribute("progress");
|
||||
// We have to set the attribute instead of using the property because the
|
||||
// XBL binding isn't applied if the element is invisible for any reason.
|
||||
this._indicatorProgress.setAttribute("value", Math.max(aValue, 0));
|
||||
}
|
||||
return aValue;
|
||||
},
|
||||
_percentComplete: null,
|
||||
|
||||
/**
|
||||
* Indicates whether the progress won't advance because of a paused state.
|
||||
* Setting this property forces a paused progress bar to be displayed, even if
|
||||
* the current progress information is unavailable.
|
||||
*/
|
||||
set paused(aValue)
|
||||
{
|
||||
if (!this._operational) {
|
||||
return this._paused;
|
||||
}
|
||||
|
||||
if (this._paused != aValue) {
|
||||
this._paused = aValue;
|
||||
if (this._paused) {
|
||||
this.indicator.setAttribute("paused", "true")
|
||||
} else {
|
||||
this.indicator.removeAttribute("paused");
|
||||
}
|
||||
}
|
||||
return aValue;
|
||||
},
|
||||
_paused: false,
|
||||
|
||||
/**
|
||||
* Set when the indicator should draw user attention to itself.
|
||||
*/
|
||||
set attention(aValue)
|
||||
{
|
||||
if (!this._operational) {
|
||||
return this._attention;
|
||||
}
|
||||
|
||||
if (this._attention != aValue) {
|
||||
this._attention = aValue;
|
||||
if (aValue) {
|
||||
this.indicator.setAttribute("attention", "true")
|
||||
} else {
|
||||
this.indicator.removeAttribute("attention");
|
||||
}
|
||||
}
|
||||
return aValue;
|
||||
},
|
||||
_attention: false,
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// User interface event functions
|
||||
|
||||
onWindowUnload: function DIV_onWindowUnload()
|
||||
{
|
||||
// This function is registered as an event listener, we can't use "this".
|
||||
DownloadsIndicatorView.ensureTerminated();
|
||||
},
|
||||
|
||||
onCommand: function DIV_onCommand(aEvent)
|
||||
{
|
||||
if (DownloadsCommon.useToolkitUI) {
|
||||
// The panel won't suppress attention for us, we need to clear now.
|
||||
DownloadsCommon.indicatorData.attention = false;
|
||||
}
|
||||
|
||||
BrowserDownloadsUI();
|
||||
|
||||
aEvent.stopPropagation();
|
||||
},
|
||||
|
||||
onDragOver: function DIV_onDragOver(aEvent)
|
||||
{
|
||||
browserDragAndDrop.dragOver(aEvent);
|
||||
},
|
||||
|
||||
onDragExit: function () { },
|
||||
|
||||
onDrop: function DIV_onDrop(aEvent)
|
||||
{
|
||||
let name = {};
|
||||
let url = browserDragAndDrop.drop(aEvent, name);
|
||||
if (url) {
|
||||
saveURL(url, name.value, null, true, true);
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a reference to the main indicator element, or null if the element
|
||||
* is not present in the browser window yet.
|
||||
*/
|
||||
get indicator()
|
||||
{
|
||||
let indicator = document.getElementById("downloads-indicator");
|
||||
if (!indicator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Once the element is loaded, it will never be unloaded.
|
||||
delete this.indicator;
|
||||
return this.indicator = indicator;
|
||||
},
|
||||
|
||||
get indicatorAnchor()
|
||||
{
|
||||
delete this.indicatorAnchor;
|
||||
return this.indicatorAnchor =
|
||||
document.getElementById("downloads-indicator-anchor");
|
||||
},
|
||||
|
||||
get _indicatorCounter()
|
||||
{
|
||||
delete this._indicatorCounter;
|
||||
return this._indicatorCounter =
|
||||
document.getElementById("downloads-indicator-counter");
|
||||
},
|
||||
|
||||
get _indicatorProgress()
|
||||
{
|
||||
delete this._indicatorProgress;
|
||||
return this._indicatorProgress =
|
||||
document.getElementById("downloads-indicator-progress");
|
||||
}
|
||||
};
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0"?>
|
||||
# -*- Mode: HTML; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
# vim: set ts=2 et sw=2 tw=80:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/content/downloads/downloads.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/downloads/downloads.css"?>
|
||||
|
||||
<!DOCTYPE overlay SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
|
||||
|
||||
<overlay xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
id="indicatorOverlay">
|
||||
|
||||
<popupset>
|
||||
<!-- The downloads indicator is placed in its final toolbar location
|
||||
programmatically, and can be shown temporarily even when its
|
||||
placeholder is removed from the toolbars. Its initial location within
|
||||
the document must not be a toolbar or the toolbar palette, otherwise the
|
||||
toolbar handling code could remove it from the document. -->
|
||||
<toolbarbutton id="downloads-indicator"
|
||||
class="toolbarbutton-1 chromeclass-toolbar-additional"
|
||||
tooltiptext="&indicator.tooltiptext;"
|
||||
collapsed="true"
|
||||
oncommand="DownloadsIndicatorView.onCommand(event);"
|
||||
ondrop="DownloadsIndicatorView.onDrop(event);"
|
||||
ondragover="DownloadsIndicatorView.onDragOver(event);"
|
||||
ondragenter="DownloadsIndicatorView.onDragOver(event);"
|
||||
ondragleave="DownloadsIndicatorView.onDragLeave(event);">
|
||||
<!-- The panel's anchor area is smaller than the outer button, but must
|
||||
always be visible and must not move or resize when the indicator
|
||||
state changes, otherwise the panel could change its position or lose
|
||||
its arrow unexpectedly. -->
|
||||
<stack id="downloads-indicator-anchor"
|
||||
class="toolbarbutton-icon">
|
||||
<vbox id="downloads-indicator-progress-area"
|
||||
pack="center">
|
||||
<description id="downloads-indicator-counter"/>
|
||||
<progressmeter id="downloads-indicator-progress"
|
||||
class="plain"
|
||||
min="0"
|
||||
max="100"/>
|
||||
</vbox>
|
||||
<vbox id="downloads-indicator-icon"/>
|
||||
<vbox id="downloads-indicator-notification"/>
|
||||
</stack>
|
||||
</toolbarbutton>
|
||||
</popupset>
|
||||
</overlay>
|
|
@ -0,0 +1,7 @@
|
|||
browser.jar:
|
||||
* content/browser/downloads/download.xml (content/download.xml)
|
||||
content/browser/downloads/downloads.css (content/downloads.css)
|
||||
content/browser/downloads/downloads.js (content/downloads.js)
|
||||
* content/browser/downloads/downloadsOverlay.xul (content/downloadsOverlay.xul)
|
||||
content/browser/downloads/indicator.js (content/indicator.js)
|
||||
* content/browser/downloads/indicatorOverlay.xul (content/indicatorOverlay.xul)
|
|
@ -0,0 +1,4 @@
|
|||
component {49507fe5-2cee-4824-b6a3-e999150ce9b8} DownloadsStartup.js
|
||||
contract @mozilla.org/browser/downloadsstartup;1 {49507fe5-2cee-4824-b6a3-e999150ce9b8}
|
||||
category app-startup DownloadsStartup service,@mozilla.org/browser/downloadsstartup;1
|
||||
component {4d99321e-d156-455b-81f7-e7aa2308134f} DownloadsUI.js
|
|
@ -0,0 +1,242 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* This component listens to notifications for startup, shutdown and session
|
||||
* restore, controlling which downloads should be loaded from the database.
|
||||
*
|
||||
* To avoid affecting startup performance, this component monitors the current
|
||||
* session restore state, but defers the actual downloads data manipulation
|
||||
* until the Download Manager service is loaded.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Globals
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
|
||||
"resource:///modules/DownloadsCommon.jsm");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gSessionStartup",
|
||||
"@mozilla.org/browser/sessionstartup;1",
|
||||
"nsISessionStartup");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gPrivateBrowsingService",
|
||||
"@mozilla.org/privatebrowsing;1",
|
||||
"nsIPrivateBrowsingService");
|
||||
|
||||
const kObservedTopics = [
|
||||
"sessionstore-windows-restored",
|
||||
"sessionstore-browser-state-restored",
|
||||
"download-manager-initialized",
|
||||
"download-manager-change-retention",
|
||||
"private-browsing-transition-complete",
|
||||
"browser-lastwindow-close-granted",
|
||||
"quit-application",
|
||||
"profile-change-teardown",
|
||||
];
|
||||
|
||||
/**
|
||||
* CID of our implementation of nsIDownloadManagerUI.
|
||||
*/
|
||||
const kDownloadsUICid = Components.ID("{4d99321e-d156-455b-81f7-e7aa2308134f}");
|
||||
|
||||
/**
|
||||
* Contract ID of the service implementing nsIDownloadManagerUI.
|
||||
*/
|
||||
const kDownloadsUIContractId = "@mozilla.org/download-manager-ui;1";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// DownloadsStartup
|
||||
|
||||
function DownloadsStartup() { }
|
||||
|
||||
DownloadsStartup.prototype = {
|
||||
classID: Components.ID("{49507fe5-2cee-4824-b6a3-e999150ce9b8}"),
|
||||
|
||||
_xpcom_factory: XPCOMUtils.generateSingletonFactory(DownloadsStartup),
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// nsISupports
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// nsIObserver
|
||||
|
||||
observe: function DS_observe(aSubject, aTopic, aData)
|
||||
{
|
||||
switch (aTopic) {
|
||||
case "app-startup":
|
||||
kObservedTopics.forEach(
|
||||
function (topic) Services.obs.addObserver(this, topic, true),
|
||||
this);
|
||||
|
||||
// Override Toolkit's nsIDownloadManagerUI implementation with our own.
|
||||
// This must be done at application startup and not in the manifest to
|
||||
// ensure that our implementation overrides the original one.
|
||||
Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
|
||||
.registerFactory(kDownloadsUICid, "",
|
||||
kDownloadsUIContractId, null);
|
||||
break;
|
||||
|
||||
case "sessionstore-windows-restored":
|
||||
case "sessionstore-browser-state-restored":
|
||||
// Unless there is no saved session, there is a chance that we are
|
||||
// starting up after a restart or a crash. We should check the disk
|
||||
// database to see if there are completed downloads to recover and show
|
||||
// in the panel, in addition to in-progress downloads.
|
||||
if (gSessionStartup.sessionType != Ci.nsISessionStartup.NO_SESSION) {
|
||||
this._recoverAllDownloads = true;
|
||||
}
|
||||
this._ensureDataLoaded();
|
||||
break;
|
||||
|
||||
case "download-manager-initialized":
|
||||
// Don't initialize the JavaScript data and user interface layer if we
|
||||
// are initializing the Download Manager service during shutdown.
|
||||
if (this._shuttingDown) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Start receiving events for active and new downloads before we return
|
||||
// from this observer function. We can't defer the execution of this
|
||||
// step, to ensure that we don't lose events raised in the meantime.
|
||||
DownloadsCommon.data.initializeDataLink(
|
||||
aSubject.QueryInterface(Ci.nsIDownloadManager));
|
||||
|
||||
this._downloadsServiceInitialized = true;
|
||||
|
||||
// Since this notification is generated during the getService call and
|
||||
// we need to get the Download Manager service ourselves, we must post
|
||||
// the handler on the event queue to be executed later.
|
||||
Services.tm.mainThread.dispatch(this._ensureDataLoaded.bind(this),
|
||||
Ci.nsIThread.DISPATCH_NORMAL);
|
||||
break;
|
||||
|
||||
case "download-manager-change-retention":
|
||||
// When the panel interface is enabled, we use a different preference to
|
||||
// determine whether downloads should be removed from view as soon as
|
||||
// they are finished. We do this to allow proper migration to the new
|
||||
// feature when using the same profile on multiple versions of the
|
||||
// product (bug 697678).
|
||||
if (!DownloadsCommon.useToolkitUI) {
|
||||
let removeFinishedDownloads = Services.prefs.getBoolPref(
|
||||
"browser.download.panel.removeFinishedDownloads");
|
||||
aSubject.QueryInterface(Ci.nsISupportsPRInt32)
|
||||
.data = removeFinishedDownloads ? 0 : 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case "private-browsing-transition-complete":
|
||||
// Ensure that persistent data is reloaded only when the database
|
||||
// connection is available again.
|
||||
this._ensureDataLoaded();
|
||||
break;
|
||||
|
||||
case "browser-lastwindow-close-granted":
|
||||
// When using the panel interface, downloads that are already completed
|
||||
// should be removed when the last full browser window is closed. This
|
||||
// event is invoked only if the application is not shutting down yet.
|
||||
// If the Download Manager service is not initialized, we don't want to
|
||||
// initialize it just to clean up completed downloads, because they can
|
||||
// be present only in case there was a browser crash or restart.
|
||||
if (this._downloadsServiceInitialized &&
|
||||
!DownloadsCommon.useToolkitUI) {
|
||||
Services.downloads.cleanUp();
|
||||
}
|
||||
break;
|
||||
|
||||
case "quit-application":
|
||||
// When the application is shutting down, we must free all resources in
|
||||
// addition to cleaning up completed downloads. If the Download Manager
|
||||
// service is not initialized, we don't want to initialize it just to
|
||||
// clean up completed downloads, because they can be present only in
|
||||
// case there was a browser crash or restart.
|
||||
this._shuttingDown = true;
|
||||
if (!this._downloadsServiceInitialized) {
|
||||
break;
|
||||
}
|
||||
|
||||
DownloadsCommon.data.terminateDataLink();
|
||||
|
||||
// When using the panel interface, downloads that are already completed
|
||||
// should be removed when quitting the application.
|
||||
if (!DownloadsCommon.useToolkitUI && aData != "restart") {
|
||||
this._cleanupOnShutdown = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case "profile-change-teardown":
|
||||
// If we need to clean up, we must do it synchronously after all the
|
||||
// "quit-application" listeners are invoked, so that the Download
|
||||
// Manager service has a chance to pause or cancel in-progress downloads
|
||||
// before we remove completed downloads from the list. Note that, since
|
||||
// "quit-application" was invoked, we've already exited Private Browsing
|
||||
// Mode, thus we are always working on the disk database.
|
||||
if (this._cleanupOnShutdown) {
|
||||
Services.downloads.cleanUp();
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// Private
|
||||
|
||||
/**
|
||||
* Indicates whether we should load all downloads from the previous session,
|
||||
* including completed items as well as active downloads.
|
||||
*/
|
||||
_recoverAllDownloads: false,
|
||||
|
||||
/**
|
||||
* Indicates whether the Download Manager service has been initialized. This
|
||||
* flag is required because we want to avoid accessing the service immediately
|
||||
* at browser startup. The service will start when the user first requests a
|
||||
* download, or some time after browser startup.
|
||||
*/
|
||||
_downloadsServiceInitialized: false,
|
||||
|
||||
/**
|
||||
* True while we are processing the "quit-application" event, and later.
|
||||
*/
|
||||
_shuttingDown: false,
|
||||
|
||||
/**
|
||||
* True during shutdown if we need to remove completed downloads.
|
||||
*/
|
||||
_cleanupOnShutdown: false,
|
||||
|
||||
/**
|
||||
* Ensures that persistent download data is reloaded at the appropriate time.
|
||||
*/
|
||||
_ensureDataLoaded: function DS_ensureDataLoaded()
|
||||
{
|
||||
if (!this._downloadsServiceInitialized ||
|
||||
gPrivateBrowsingService.privateBrowsingEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the previous session has been already restored, then we ensure that
|
||||
// all the downloads are loaded. Otherwise, we only ensure that the active
|
||||
// downloads from the previous session are loaded.
|
||||
DownloadsCommon.data.ensurePersistentDataLoaded(!this._recoverAllDownloads);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Module
|
||||
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([DownloadsStartup]);
|
|
@ -0,0 +1,125 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* This component implements the nsIDownloadManagerUI interface and opens the
|
||||
* downloads panel in the most recent browser window when requested.
|
||||
*
|
||||
* If a specific preference is set, this component transparently forwards all
|
||||
* calls to the original implementation in Toolkit, that shows the window UI.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Globals
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
|
||||
"resource:///modules/DownloadsCommon.jsm");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gBrowserGlue",
|
||||
"@mozilla.org/browser/browserglue;1",
|
||||
"nsIBrowserGlue");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// DownloadsUI
|
||||
|
||||
function DownloadsUI()
|
||||
{
|
||||
XPCOMUtils.defineLazyGetter(this, "_toolkitUI", function () {
|
||||
// Create Toolkit's nsIDownloadManagerUI implementation.
|
||||
return Components.classesByID["{7dfdf0d1-aff6-4a34-bad1-d0fe74601642}"]
|
||||
.getService(Ci.nsIDownloadManagerUI);
|
||||
});
|
||||
}
|
||||
|
||||
DownloadsUI.prototype = {
|
||||
classID: Components.ID("{4d99321e-d156-455b-81f7-e7aa2308134f}"),
|
||||
|
||||
_xpcom_factory: XPCOMUtils.generateSingletonFactory(DownloadsUI),
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// nsISupports
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDownloadManagerUI]),
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// nsIDownloadManagerUI
|
||||
|
||||
show: function DUI_show(aWindowContext, aID, aReason)
|
||||
{
|
||||
if (DownloadsCommon.useToolkitUI) {
|
||||
this._toolkitUI.show(aWindowContext, aID, aReason);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aReason) {
|
||||
aReason = Ci.nsIDownloadManagerUI.REASON_USER_INTERACTED;
|
||||
}
|
||||
|
||||
if (aReason == Ci.nsIDownloadManagerUI.REASON_NEW_DOWNLOAD) {
|
||||
// New download notifications are already handled by the panel service.
|
||||
// We don't handle them here because we don't want them to depend on the
|
||||
// "browser.download.manager.showWhenStarting" and
|
||||
// "browser.download.manager.focusWhenStarting" preferences.
|
||||
return;
|
||||
}
|
||||
|
||||
// Show the panel in the most recent browser window, if present.
|
||||
let browserWin = gBrowserGlue.getMostRecentBrowserWindow();
|
||||
if (browserWin) {
|
||||
browserWin.focus();
|
||||
browserWin.DownloadsPanel.showPanel();
|
||||
return;
|
||||
}
|
||||
|
||||
// If no browser window is visible and the user requested to show the
|
||||
// current downloads, try and open a new window. We'll open the panel when
|
||||
// delayed loading is finished.
|
||||
Services.obs.addObserver(function DUIO_observe(aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(DUIO_observe, aTopic);
|
||||
aSubject.DownloadsPanel.showPanel();
|
||||
}, "browser-delayed-startup-finished", false);
|
||||
|
||||
// We must really build an empty arguments list for the new window.
|
||||
let windowFirstArg = Cc["@mozilla.org/supports-string;1"]
|
||||
.createInstance(Ci.nsISupportsString);
|
||||
let windowArgs = Cc["@mozilla.org/supports-array;1"]
|
||||
.createInstance(Ci.nsISupportsArray);
|
||||
windowArgs.AppendElement(windowFirstArg);
|
||||
Services.ww.openWindow(null, "chrome://browser/content/browser.xul",
|
||||
null, "chrome,dialog=no,all", windowArgs);
|
||||
},
|
||||
|
||||
get visible()
|
||||
{
|
||||
if (DownloadsCommon.useToolkitUI) {
|
||||
return this._toolkitUI.visible;
|
||||
}
|
||||
|
||||
let browserWin = gBrowserGlue.getMostRecentBrowserWindow();
|
||||
return browserWin ? browserWin.DownloadsPanel.isPanelShowing : false;
|
||||
},
|
||||
|
||||
getAttention: function DUI_getAttention()
|
||||
{
|
||||
if (DownloadsCommon.useToolkitUI) {
|
||||
this._toolkitUI.getAttention();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Module
|
||||
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([DownloadsUI]);
|
|
@ -0,0 +1,22 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
EXTRA_COMPONENTS = \
|
||||
BrowserDownloads.manifest \
|
||||
DownloadsStartup.js \
|
||||
DownloadsUI.js \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_JS_MODULES = \
|
||||
DownloadsCommon.jsm \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -0,0 +1,17 @@
|
|||
# Any copyright is dedicated to the Public Domain.
|
||||
# http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
relativesrcdir = browser/components/downloads/test
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
XPCSHELL_TESTS = unit
|
||||
|
||||
DIRS = browser
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -0,0 +1,20 @@
|
|||
# Any copyright is dedicated to the Public Domain.
|
||||
# http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
DEPTH = ../../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
relativesrcdir = browser/components/downloads/test/browser
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_BROWSER_FILES = \
|
||||
browser_basic_functionality.js \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_BROWSER_FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Make sure the downloads panel can display items in the right order and
|
||||
* contains the expected data.
|
||||
*/
|
||||
function gen_test()
|
||||
{
|
||||
// Display one of each download state.
|
||||
const DownloadData = [
|
||||
{ endTime: 1180493839859239, state: nsIDM.DOWNLOAD_NOTSTARTED },
|
||||
{ endTime: 1180493839859238, state: nsIDM.DOWNLOAD_DOWNLOADING },
|
||||
{ endTime: 1180493839859237, state: nsIDM.DOWNLOAD_PAUSED },
|
||||
{ endTime: 1180493839859236, state: nsIDM.DOWNLOAD_SCANNING },
|
||||
{ endTime: 1180493839859235, state: nsIDM.DOWNLOAD_QUEUED },
|
||||
{ endTime: 1180493839859234, state: nsIDM.DOWNLOAD_FINISHED },
|
||||
{ endTime: 1180493839859233, state: nsIDM.DOWNLOAD_FAILED },
|
||||
{ endTime: 1180493839859232, state: nsIDM.DOWNLOAD_CANCELED },
|
||||
{ endTime: 1180493839859231, state: nsIDM.DOWNLOAD_BLOCKED_PARENTAL },
|
||||
{ endTime: 1180493839859230, state: nsIDM.DOWNLOAD_DIRTY },
|
||||
{ endTime: 1180493839859229, state: nsIDM.DOWNLOAD_BLOCKED_POLICY },
|
||||
];
|
||||
|
||||
try {
|
||||
// Ensure that state is reset in case previous tests didn't finish.
|
||||
for (let yy in gen_resetState()) yield;
|
||||
|
||||
// Populate the downloads database with the data required by this test.
|
||||
for (let yy in gen_addDownloadRows(DownloadData)) yield;
|
||||
|
||||
// Open the user interface and wait for data to be fully loaded.
|
||||
for (let yy in gen_openPanel()) yield;
|
||||
|
||||
// Test item data and count. This also tests the ordering of the display.
|
||||
let richlistbox = document.getElementById("downloadsListBox");
|
||||
is(richlistbox.children.length, DownloadData.length,
|
||||
"There is the correct number of richlistitems");
|
||||
for (let i = 0; i < richlistbox.children.length; i++) {
|
||||
let element = richlistbox.children[i];
|
||||
let dataItem = new DownloadsViewItemController(element).dataItem;
|
||||
is(dataItem.target, DownloadData[i].name, "Download names match up");
|
||||
is(dataItem.state, DownloadData[i].state, "Download states match up");
|
||||
is(dataItem.file, DownloadData[i].target, "Download targets match up");
|
||||
is(dataItem.uri, DownloadData[i].source, "Download sources match up");
|
||||
}
|
||||
} finally {
|
||||
// Clean up when the test finishes.
|
||||
for (let yy in gen_resetState()) yield;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Provides infrastructure for automated download components tests.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Globals
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
const nsIDM = Ci.nsIDownloadManager;
|
||||
|
||||
let gTestTargetFile = FileUtils.getFile("TmpD", ["dm-ui-test.file"]);
|
||||
gTestTargetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
|
||||
registerCleanupFunction(function () {
|
||||
gTestTargetFile.remove(false);
|
||||
});
|
||||
|
||||
/**
|
||||
* This objects contains a property for each column in the downloads table.
|
||||
*/
|
||||
let gDownloadRowTemplate = {
|
||||
name: "test-download.txt",
|
||||
source: "http://www.example.com/test-download.txt",
|
||||
target: NetUtil.newURI(gTestTargetFile).spec,
|
||||
startTime: 1180493839859230,
|
||||
endTime: 1180493839859234,
|
||||
state: nsIDM.DOWNLOAD_FINISHED,
|
||||
currBytes: 0,
|
||||
maxBytes: -1,
|
||||
preferredAction: 0,
|
||||
autoResume: 0
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Infrastructure
|
||||
|
||||
// All test are run through the test runner.
|
||||
function test()
|
||||
{
|
||||
testRunner.runTest(this.gen_test);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a browser-chrome test defined through a generator function.
|
||||
*
|
||||
* This object is a singleton, initialized automatically when this script is
|
||||
* included. Every browser-chrome test file includes a new copy of this object.
|
||||
*/
|
||||
var testRunner = {
|
||||
_testIterator: null,
|
||||
_lastEventResult: undefined,
|
||||
_testRunning: false,
|
||||
_eventRaised: false,
|
||||
|
||||
// --- Main test runner ---
|
||||
|
||||
/**
|
||||
* Runs the test described by the provided generator function asynchronously.
|
||||
*
|
||||
* Calling yield in the generator will cause it to wait until continueTest is
|
||||
* called. The parameter provided to continueTest will be the return value of
|
||||
* the yield operator.
|
||||
*
|
||||
* @param aGenerator
|
||||
* Test generator function. The function will be called with no
|
||||
* arguments to retrieve its iterator.
|
||||
*/
|
||||
runTest: function TR_runTest(aGenerator) {
|
||||
waitForExplicitFinish();
|
||||
testRunner._testIterator = aGenerator();
|
||||
testRunner.continueTest();
|
||||
},
|
||||
|
||||
/**
|
||||
* Continues the currently running test.
|
||||
*
|
||||
* @param aEventResult
|
||||
* This will be the return value of the yield operator in the test.
|
||||
*/
|
||||
continueTest: function TR_continueTest(aEventResult) {
|
||||
// Store the last event result, or set it to undefined.
|
||||
testRunner._lastEventResult = aEventResult;
|
||||
|
||||
// Never reenter the main loop, but notify that the event has been raised.
|
||||
if (testRunner._testRunning) {
|
||||
testRunner._eventRaised = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Enter the main iteration loop.
|
||||
testRunner._testRunning = true;
|
||||
try {
|
||||
do {
|
||||
// Call the iterator, but don't leave the loop if the expected event is
|
||||
// raised during the execution of the generator.
|
||||
testRunner._eventRaised = false;
|
||||
testRunner._testIterator.send(testRunner._lastEventResult);
|
||||
} while (testRunner._eventRaised);
|
||||
}
|
||||
catch (e) {
|
||||
// This block catches exceptions raised by the generator, including the
|
||||
// normal StopIteration exception. Unexpected exceptions are reported as
|
||||
// test failures.
|
||||
if (!(e instanceof StopIteration))
|
||||
ok(false, e);
|
||||
// In any case, stop the tests in this file.
|
||||
finish();
|
||||
}
|
||||
|
||||
// Wait for the next event or finish.
|
||||
testRunner._testRunning = false;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Asynchronous generator-based support subroutines
|
||||
|
||||
//
|
||||
// The following functions are all generators that can be used inside the main
|
||||
// test generator to perform specific tasks asynchronously. To invoke these
|
||||
// subroutines correctly, an iteration syntax should be used:
|
||||
//
|
||||
// for (let yy in gen_example("Parameter")) yield;
|
||||
//
|
||||
|
||||
function gen_resetState()
|
||||
{
|
||||
let statement = Services.downloads.DBConnection.createAsyncStatement(
|
||||
"DELETE FROM moz_downloads");
|
||||
try {
|
||||
statement.executeAsync({
|
||||
handleResult: function(aResultSet) { },
|
||||
handleError: function(aError)
|
||||
{
|
||||
Cu.reportError(aError);
|
||||
},
|
||||
handleCompletion: function(aReason)
|
||||
{
|
||||
testRunner.continueTest();
|
||||
}
|
||||
});
|
||||
yield;
|
||||
} finally {
|
||||
statement.finalize();
|
||||
}
|
||||
|
||||
// Ensure that the panel is closed and data is unloaded.
|
||||
DownloadsCommon.data.clear();
|
||||
DownloadsCommon.data._loadState = DownloadsCommon.data.kLoadNone;
|
||||
|
||||
// Wait for focus on the main window.
|
||||
waitForFocus(testRunner.continueTest);
|
||||
yield;
|
||||
}
|
||||
|
||||
function gen_addDownloadRows(aDataRows)
|
||||
{
|
||||
let columnNames = Object.keys(gDownloadRowTemplate).join(", ");
|
||||
let parameterNames = Object.keys(gDownloadRowTemplate)
|
||||
.map(function(n) ":" + n)
|
||||
.join(", ");
|
||||
let statement = Services.downloads.DBConnection.createAsyncStatement(
|
||||
"INSERT INTO moz_downloads (" + columnNames +
|
||||
") VALUES(" + parameterNames + ")");
|
||||
try {
|
||||
// Execute the statement for each of the provided downloads in reverse.
|
||||
for (let i = aDataRows.length - 1; i >= 0; i--) {
|
||||
let dataRow = aDataRows[i];
|
||||
|
||||
// Populate insert parameters from the provided data.
|
||||
for (let columnName in gDownloadRowTemplate) {
|
||||
if (!(columnName in dataRow)) {
|
||||
// Update the provided row object with data from the global template,
|
||||
// for columns whose value is not provided explicitly.
|
||||
dataRow[columnName] = gDownloadRowTemplate[columnName];
|
||||
}
|
||||
statement.params[columnName] = dataRow[columnName];
|
||||
}
|
||||
|
||||
// Run the statement asynchronously and wait.
|
||||
statement.executeAsync({
|
||||
handleResult: function(aResultSet) { },
|
||||
handleError: function(aError)
|
||||
{
|
||||
Cu.reportError(aError);
|
||||
},
|
||||
handleCompletion: function(aReason)
|
||||
{
|
||||
testRunner.continueTest();
|
||||
}
|
||||
});
|
||||
yield;
|
||||
|
||||
// At each iteration, ensure that the end time in the global template is
|
||||
// distinct, as this column is used to sort each download in its category.
|
||||
gDownloadRowTemplate.endTime++;
|
||||
}
|
||||
} finally {
|
||||
statement.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
function gen_openPanel(aData)
|
||||
{
|
||||
// Hook to wait until the test data has been loaded.
|
||||
let originalOnViewLoadCompleted = DownloadsPanel.onViewLoadCompleted;
|
||||
DownloadsPanel.onViewLoadCompleted = function () {
|
||||
DownloadsPanel.onViewLoadCompleted = originalOnViewLoadCompleted;
|
||||
originalOnViewLoadCompleted.apply(this);
|
||||
testRunner.continueTest();
|
||||
};
|
||||
|
||||
// Start loading all the downloads from the database asynchronously.
|
||||
DownloadsCommon.data.ensurePersistentDataLoaded(false);
|
||||
|
||||
// Wait for focus on the main window.
|
||||
waitForFocus(testRunner.continueTest);
|
||||
yield;
|
||||
|
||||
// Open the downloads panel, waiting until loading is completed.
|
||||
DownloadsPanel.showPanel();
|
||||
yield;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Provides infrastructure for automated download components tests.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Globals
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource:///modules/DownloadsCommon.jsm");
|
|
@ -0,0 +1,37 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests for the functions located directly in the "DownloadsCommon" object.
|
||||
*/
|
||||
|
||||
function testFormatTimeLeft(aSeconds, aExpectedValue, aExpectedUnitString)
|
||||
{
|
||||
let expected = "";
|
||||
if (aExpectedValue) {
|
||||
// Format the expected result based on the current language.
|
||||
expected = DownloadsCommon.strings[aExpectedUnitString](aExpectedValue);
|
||||
}
|
||||
do_check_eq(DownloadsCommon.formatTimeLeft(aSeconds), expected);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
testFormatTimeLeft( 0, "", "");
|
||||
testFormatTimeLeft( 1, "1", "shortTimeLeftSeconds");
|
||||
testFormatTimeLeft( 29, "29", "shortTimeLeftSeconds");
|
||||
testFormatTimeLeft( 30, "30", "shortTimeLeftSeconds");
|
||||
testFormatTimeLeft( 31, "1", "shortTimeLeftMinutes");
|
||||
testFormatTimeLeft( 60, "1", "shortTimeLeftMinutes");
|
||||
testFormatTimeLeft( 89, "1", "shortTimeLeftMinutes");
|
||||
testFormatTimeLeft( 90, "2", "shortTimeLeftMinutes");
|
||||
testFormatTimeLeft( 91, "2", "shortTimeLeftMinutes");
|
||||
testFormatTimeLeft( 3600, "1", "shortTimeLeftHours");
|
||||
testFormatTimeLeft( 86400, "24", "shortTimeLeftHours");
|
||||
testFormatTimeLeft( 169200, "47", "shortTimeLeftHours");
|
||||
testFormatTimeLeft( 172800, "2", "shortTimeLeftDays");
|
||||
testFormatTimeLeft(8553600, "99", "shortTimeLeftDays");
|
||||
testFormatTimeLeft(8640000, "99", "shortTimeLeftDays");
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
[DEFAULT]
|
||||
head = head.js
|
||||
tail =
|
||||
|
||||
[test_DownloadsCommon.js]
|
|
@ -1,3 +1,16 @@
|
|||
# WebappRT doesn't need these instructions, and they don't necessarily work
|
||||
# with it, but it does use a GRE directory that the GRE shares with Firefox,
|
||||
# so in order to prevent the instructions from being processed for WebappRT,
|
||||
# we need to restrict them to the applications that depend on them, i.e.:
|
||||
#
|
||||
# b2g: {3c2e2abc-06d4-11e1-ac3b-374f68613e61}
|
||||
# browser: {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
|
||||
# mobile/android: {aa3c5121-dab2-40e2-81ca-7ea25febc110}
|
||||
# mobile/xul: {a23983c0-fd0e-11dc-95ff-0800200c9a66}
|
||||
#
|
||||
# In theory we should do this for all these instructions, but in practice it is
|
||||
# sufficient to do it for the app-startup one, and the file is simpler that way.
|
||||
|
||||
component {229fa115-9412-4d32-baf3-2fc407f76fb1} FeedConverter.js
|
||||
contract @mozilla.org/streamconv;1?from=application/vnd.mozilla.maybe.feed&to=*/* {229fa115-9412-4d32-baf3-2fc407f76fb1}
|
||||
contract @mozilla.org/streamconv;1?from=application/vnd.mozilla.maybe.video.feed&to=*/* {229fa115-9412-4d32-baf3-2fc407f76fb1}
|
||||
|
@ -13,4 +26,4 @@ contract @mozilla.org/browser/feeds/result-writer;1 {49bb6593-3aff-4eb3-a068-271
|
|||
category JavaScript-global-constructor BrowserFeedWriter @mozilla.org/browser/feeds/result-writer;1
|
||||
component {792a7e82-06a0-437c-af63-b2d12e808acc} WebContentConverter.js
|
||||
contract @mozilla.org/embeddor.implemented/web-content-handler-registrar;1 {792a7e82-06a0-437c-af63-b2d12e808acc}
|
||||
category app-startup WebContentConverter service,@mozilla.org/embeddor.implemented/web-content-handler-registrar;1
|
||||
category app-startup WebContentConverter service,@mozilla.org/embeddor.implemented/web-content-handler-registrar;1 application={3c2e2abc-06d4-11e1-ac3b-374f68613e61} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} application={aa3c5121-dab2-40e2-81ca-7ea25febc110} application={a23983c0-fd0e-11dc-95ff-0800200c9a66}
|
||||
|
|
|
@ -4,5 +4,7 @@ component {4cec1de4-1671-4fc3-a53e-6c539dc77a26} ChromeProfileMigrator.js
|
|||
contract @mozilla.org/profile/migrator;1?app=browser&type=chrome {4cec1de4-1671-4fc3-a53e-6c539dc77a26}
|
||||
component {91185366-ba97-4438-acba-48deaca63386} FirefoxProfileMigrator.js
|
||||
contract @mozilla.org/profile/migrator;1?app=browser&type=firefox {91185366-ba97-4438-acba-48deaca63386}
|
||||
component {3d2532e3-4932-4774-b7ba-968f5899d3a4} IEProfileMigrator.js
|
||||
contract @mozilla.org/profile/migrator;1?app=browser&type=ie {3d2532e3-4932-4774-b7ba-968f5899d3a4}
|
||||
component {4b609ecf-60b2-4655-9df4-dc149e474da1} SafariProfileMigrator.js
|
||||
contract @mozilla.org/profile/migrator;1?app=browser&type=safari {4b609ecf-60b2-4655-9df4-dc149e474da1}
|
||||
|
|
|
@ -0,0 +1,678 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
const kMainKey = "Software\\Microsoft\\Internet Explorer\\Main";
|
||||
const kRegMultiSz = 7;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource:///modules/MigrationUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ctypes",
|
||||
"resource://gre/modules/ctypes.jsm");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Helpers.
|
||||
|
||||
let CtypesHelpers = {
|
||||
_structs: {},
|
||||
_functions: {},
|
||||
_libs: {},
|
||||
|
||||
/**
|
||||
* Must be invoked once before first use of any of the provided helpers.
|
||||
*/
|
||||
initialize: function CH_initialize() {
|
||||
const WORD = ctypes.uint16_t;
|
||||
const DWORD = ctypes.uint32_t;
|
||||
const BOOL = ctypes.int;
|
||||
|
||||
this._structs.SYSTEMTIME = new ctypes.StructType('SYSTEMTIME', [
|
||||
{wYear: WORD},
|
||||
{wMonth: WORD},
|
||||
{wDayOfWeek: WORD},
|
||||
{wDay: WORD},
|
||||
{wHour: WORD},
|
||||
{wMinute: WORD},
|
||||
{wSecond: WORD},
|
||||
{wMilliseconds: WORD}
|
||||
]);
|
||||
|
||||
this._structs.FILETIME = new ctypes.StructType('FILETIME', [
|
||||
{dwLowDateTime: DWORD},
|
||||
{dwHighDateTime: DWORD}
|
||||
]);
|
||||
|
||||
try {
|
||||
this._libs.kernel32 = ctypes.open("Kernel32");
|
||||
this._functions.FileTimeToSystemTime =
|
||||
this._libs.kernel32.declare("FileTimeToSystemTime",
|
||||
ctypes.default_abi,
|
||||
BOOL,
|
||||
this._structs.FILETIME.ptr,
|
||||
this._structs.SYSTEMTIME.ptr);
|
||||
} catch (ex) {
|
||||
this.finalize();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Must be invoked once after last use of any of the provided helpers.
|
||||
*/
|
||||
finalize: function CH_finalize() {
|
||||
this._structs = {};
|
||||
this._functions = {};
|
||||
for each (let lib in this._libs) {
|
||||
try {
|
||||
lib.close();
|
||||
} catch (ex) {}
|
||||
}
|
||||
this._libs = {};
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts a FILETIME struct (2 DWORDS), to a SYSTEMTIME struct.
|
||||
*
|
||||
* @param aTimeHi
|
||||
* Least significant DWORD.
|
||||
* @param aTimeLo
|
||||
* Most significant DWORD.
|
||||
* @return a Date object representing the converted datetime.
|
||||
*/
|
||||
fileTimeToDate: function CH_fileTimeToDate(aTimeHi, aTimeLo) {
|
||||
let fileTime = this._structs.FILETIME();
|
||||
fileTime.dwLowDateTime = aTimeLo;
|
||||
fileTime.dwHighDateTime = aTimeHi;
|
||||
let systemTime = this._structs.SYSTEMTIME();
|
||||
let result = this._functions.FileTimeToSystemTime(fileTime.address(),
|
||||
systemTime.address());
|
||||
if (result == 0)
|
||||
throw new Error(ctypes.winLastError);
|
||||
|
||||
return new Date(systemTime.wYear,
|
||||
systemTime.wMonth - 1,
|
||||
systemTime.wDay,
|
||||
systemTime.wHour,
|
||||
systemTime.wMinute,
|
||||
systemTime.wSecond,
|
||||
systemTime.wMilliseconds);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether an host is an IP (v4 or v6) address.
|
||||
*
|
||||
* @param aHost
|
||||
* The host to check.
|
||||
* @return whether aHost is an IP address.
|
||||
*/
|
||||
function hostIsIPAddress(aHost) {
|
||||
try {
|
||||
Services.eTLD.getBaseDomainFromHost(aHost);
|
||||
} catch (e if e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS) {
|
||||
return true;
|
||||
} catch (e) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely reads a value from the registry.
|
||||
*
|
||||
* @param aRoot
|
||||
* The root registry to use.
|
||||
* @param aPath
|
||||
* The registry path to the key.
|
||||
* @param aKey
|
||||
* The key name.
|
||||
* @return The key value or undefined if it doesn't exist. If the key is
|
||||
* a REG_MULTI_SZ, an array is returned.
|
||||
*/
|
||||
function readRegKey(aRoot, aPath, aKey) {
|
||||
let registry = Cc["@mozilla.org/windows-registry-key;1"].
|
||||
createInstance(Ci.nsIWindowsRegKey);
|
||||
try {
|
||||
registry.open(aRoot, aPath, Ci.nsIWindowsRegKey.ACCESS_READ);
|
||||
if (registry.hasValue(aKey)) {
|
||||
let type = registry.getValueType(aKey);
|
||||
switch (type) {
|
||||
case kRegMultiSz:
|
||||
// nsIWindowsRegKey doesn't support REG_MULTI_SZ type out of the box.
|
||||
let str = registry.readStringValue(aKey);
|
||||
return [v for each (v in str.split("\0")) if (v)];
|
||||
case Ci.nsIWindowsRegKey.TYPE_STRING:
|
||||
return registry.readStringValue(aKey);
|
||||
case Ci.nsIWindowsRegKey.TYPE_INT:
|
||||
return registry.readIntValue(aKey);
|
||||
default:
|
||||
throw new Error("Unsupported registry value.");
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
} finally {
|
||||
registry.close();
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Resources
|
||||
|
||||
function Bookmarks() {
|
||||
}
|
||||
|
||||
Bookmarks.prototype = {
|
||||
type: MigrationUtils.resourceTypes.BOOKMARKS,
|
||||
|
||||
get exists() !!this._favoritesFolder,
|
||||
|
||||
__favoritesFolder: null,
|
||||
get _favoritesFolder() {
|
||||
if (!this.__favoritesFolder) {
|
||||
let favoritesFolder = Services.dirsvc.get("Favs", Ci.nsIFile);
|
||||
if (favoritesFolder.exists() && favoritesFolder.isReadable())
|
||||
this.__favoritesFolder = favoritesFolder;
|
||||
}
|
||||
return this.__favoritesFolder;
|
||||
},
|
||||
|
||||
__toolbarFolderName: null,
|
||||
get _toolbarFolderName() {
|
||||
if (!this.__toolbarFolderName) {
|
||||
// Retrieve the name of IE's favorites subfolder that holds the bookmarks
|
||||
// in the toolbar. This was previously stored in the registry and changed
|
||||
// in IE7 to always be called "Links".
|
||||
let folderName = readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
|
||||
"Software\\Microsoft\\Internet Explorer\\Toolbar",
|
||||
"LinksFolderName");
|
||||
this.__toolbarFolderName = folderName || "Links";
|
||||
}
|
||||
return this.__toolbarFolderName;
|
||||
},
|
||||
|
||||
migrate: function B_migrate(aCallback) {
|
||||
PlacesUtils.bookmarks.runInBatchMode({
|
||||
runBatched: (function migrateBatched() {
|
||||
// Import to the bookmarks menu.
|
||||
let destFolderId = PlacesUtils.bookmarksMenuFolderId;
|
||||
if (!MigrationUtils.isStartupMigration) {
|
||||
destFolderId =
|
||||
MigrationUtils.createImportedBookmarksFolder("IE", destFolderId);
|
||||
}
|
||||
|
||||
this._migrateFolder(this._favoritesFolder, destFolderId);
|
||||
|
||||
aCallback(true);
|
||||
}).bind(this)
|
||||
}, null);
|
||||
},
|
||||
|
||||
_migrateFolder: function B__migrateFolder(aSourceFolder, aDestFolderId) {
|
||||
// TODO (bug 741993): the favorites order is stored in the Registry, at
|
||||
// HCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\Favorites
|
||||
// Until we support it, bookmarks are imported in alphabetical order.
|
||||
let entries = aSourceFolder.directoryEntries;
|
||||
while (entries.hasMoreElements()) {
|
||||
let entry = entries.getNext().QueryInterface(Ci.nsIFile);
|
||||
|
||||
// Make sure that entry.path == entry.target to not follow .lnk folder
|
||||
// shortcuts which could lead to infinite cycles.
|
||||
if (entry.isDirectory() && entry.path == entry.target) {
|
||||
let destFolderId;
|
||||
if (entry.leafName == this._toolbarFolderName &&
|
||||
entry.parent.equals(this._favoritesFolder)) {
|
||||
// Import to the bookmarks toolbar.
|
||||
destFolderId = PlacesUtils.toolbarFolderId;
|
||||
if (!MigrationUtils.isStartupMigration) {
|
||||
destFolderId =
|
||||
MigrationUtils.createImportedBookmarksFolder("IE", destFolderId);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Import to a new folder.
|
||||
destFolderId =
|
||||
PlacesUtils.bookmarks.createFolder(aDestFolderId, entry.leafName,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX);
|
||||
}
|
||||
|
||||
if (entry.isReadable()) {
|
||||
// Recursively import the folder.
|
||||
this._migrateFolder(entry, destFolderId);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Strip the .url extension, to both check this is a valid link file,
|
||||
// and get the associated title.
|
||||
let matches = entry.leafName.match(/(.+)\.url$/);
|
||||
if (matches) {
|
||||
let fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].
|
||||
getService(Ci.nsIFileProtocolHandler);
|
||||
let uri = fileHandler.readURLFile(entry);
|
||||
let title = matches[1];
|
||||
|
||||
PlacesUtils.bookmarks.insertBookmark(aDestFolderId,
|
||||
uri,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
title);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function History() {
|
||||
}
|
||||
|
||||
History.prototype = {
|
||||
type: MigrationUtils.resourceTypes.HISTORY,
|
||||
|
||||
get exists() true,
|
||||
|
||||
__typedURLs: null,
|
||||
get _typedURLs() {
|
||||
if (!this.__typedURLs) {
|
||||
// The list of typed URLs is a sort of annotation stored in the registry.
|
||||
// Currently, IE stores 25 entries and this value is not configurable,
|
||||
// but we just keep reading up to the first non-existing entry to support
|
||||
// possible future bumps of this limit.
|
||||
this.__typedURLs = {};
|
||||
let registry = Cc["@mozilla.org/windows-registry-key;1"].
|
||||
createInstance(Ci.nsIWindowsRegKey);
|
||||
try {
|
||||
registry.open(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
|
||||
"Software\\Microsoft\\Internet Explorer\\TypedURLs",
|
||||
Ci.nsIWindowsRegKey.ACCESS_READ);
|
||||
for (let entry = 1; registry.hasValue("url" + entry); entry++) {
|
||||
let url = registry.readStringValue("url" + entry);
|
||||
this.__typedURLs[url] = true;
|
||||
}
|
||||
} catch (ex) {
|
||||
} finally {
|
||||
registry.close();
|
||||
}
|
||||
}
|
||||
return this.__typedURLs;
|
||||
},
|
||||
|
||||
migrate: function H_migrate(aCallback) {
|
||||
let places = [];
|
||||
let historyEnumerator = Cc["@mozilla.org/profile/migrator/iehistoryenumerator;1"].
|
||||
createInstance(Ci.nsISimpleEnumerator);
|
||||
while (historyEnumerator.hasMoreElements()) {
|
||||
let entry = historyEnumerator.getNext().QueryInterface(Ci.nsIPropertyBag2);
|
||||
let uri = entry.get("uri").QueryInterface(Ci.nsIURI);
|
||||
// MSIE stores some types of URLs in its history that we don't handle,
|
||||
// like HTMLHelp and others. Since we don't properly map handling for
|
||||
// all of them we just avoid importing them.
|
||||
if (["http", "https", "ftp", "file"].indexOf(uri.scheme) == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let title = entry.get("title");
|
||||
// Embed visits have no title and don't need to be imported.
|
||||
if (title.length == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The typed urls are already fixed-up, so we can use them for comparison.
|
||||
let transitionType = this._typedURLs[uri.spec] ?
|
||||
Ci.nsINavHistoryService.TRANSITION_TYPED :
|
||||
Ci.nsINavHistoryService.TRANSITION_LINK;
|
||||
let lastVisitTime = entry.get("time");
|
||||
|
||||
places.push(
|
||||
{ uri: uri,
|
||||
title: title,
|
||||
visits: [{ transitionType: transitionType,
|
||||
visitDate: lastVisitTime }]
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Check whether there is any history to import.
|
||||
if (places.length == 0) {
|
||||
aCallback(true);
|
||||
return;
|
||||
}
|
||||
|
||||
PlacesUtils.asyncHistory.updatePlaces(places, {
|
||||
_success: false,
|
||||
handleResult: function() {
|
||||
// Importing any entry is considered a successful import.
|
||||
this._success = true;
|
||||
},
|
||||
handleError: function() {},
|
||||
handleCompletion: function() {
|
||||
aCallback(this._success);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function Cookies() {
|
||||
}
|
||||
|
||||
Cookies.prototype = {
|
||||
type: MigrationUtils.resourceTypes.COOKIES,
|
||||
|
||||
get exists() !!this._cookiesFolder,
|
||||
|
||||
__cookiesFolder: null,
|
||||
get _cookiesFolder() {
|
||||
// Cookies are stored in txt files, in a Cookies folder whose path varies
|
||||
// across the different OS versions. CookD takes care of most of these
|
||||
// cases, though, in Windows Vista/7, UAC makes a difference.
|
||||
// If UAC is enabled, the most common destination is CookD/Low. Though,
|
||||
// if the user runs the application in administrator mode or disables UAC,
|
||||
// cookies are stored in the original CookD destination. Cause running the
|
||||
// browser in administrator mode is unsafe and discouraged, we just care
|
||||
// about the UAC state.
|
||||
if (!this.__cookiesFolder) {
|
||||
let cookiesFolder = Services.dirsvc.get("CookD", Ci.nsIFile);
|
||||
if (cookiesFolder.exists() && cookiesFolder.isReadable()) {
|
||||
// Check if UAC is enabled.
|
||||
if (Services.appinfo.QueryInterface(Ci.nsIWinAppHelper).userCanElevate) {
|
||||
cookiesFolder.append("Low");
|
||||
}
|
||||
this.__cookiesFolder = cookiesFolder;
|
||||
}
|
||||
}
|
||||
return this.__cookiesFolder;
|
||||
},
|
||||
|
||||
migrate: function C_migrate(aCallback) {
|
||||
CtypesHelpers.initialize();
|
||||
|
||||
let cookiesGenerator = (function genCookie() {
|
||||
let success = false;
|
||||
let entries = this._cookiesFolder.directoryEntries;
|
||||
while (entries.hasMoreElements()) {
|
||||
let entry = entries.getNext().QueryInterface(Ci.nsIFile);
|
||||
// Skip eventual bogus entries.
|
||||
if (!entry.isFile() || !/\.txt$/.test(entry.leafName))
|
||||
continue;
|
||||
|
||||
this._readCookieFile(entry, function(aSuccess) {
|
||||
// Importing even a single cookie file is considered a success.
|
||||
if (aSuccess)
|
||||
success = true;
|
||||
try {
|
||||
cookiesGenerator.next();
|
||||
} catch (ex) {}
|
||||
});
|
||||
|
||||
yield;
|
||||
}
|
||||
|
||||
CtypesHelpers.finalize();
|
||||
|
||||
aCallback(success);
|
||||
}).apply(this);
|
||||
cookiesGenerator.next();
|
||||
},
|
||||
|
||||
_readCookieFile: function C__readCookieFile(aFile, aCallback) {
|
||||
let fileReader = Cc["@mozilla.org/files/filereader;1"].
|
||||
createInstance(Ci.nsIDOMFileReader);
|
||||
fileReader.addEventListener("loadend", (function onLoadEnd() {
|
||||
fileReader.removeEventListener("loadend", onLoadEnd, false);
|
||||
|
||||
if (fileReader.readyState != fileReader.DONE) {
|
||||
Cu.reportError("Could not read cookie contents: " + fileReader.error);
|
||||
aCallback(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let success = true;
|
||||
try {
|
||||
this._parseCookieBuffer(fileReader.result);
|
||||
} catch (ex) {
|
||||
Components.utils.reportError("Unable to migrate cookie: " + ex);
|
||||
success = false;
|
||||
} finally {
|
||||
aCallback(success);
|
||||
}
|
||||
}).bind(this), false);
|
||||
fileReader.readAsText(File(aFile));
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses a cookie file buffer and returns an array of the contained cookies.
|
||||
*
|
||||
* The cookie file format is a newline-separated-values with a "*" used as
|
||||
* delimeter between multiple records.
|
||||
* Each cookie has the following fields:
|
||||
* - name
|
||||
* - value
|
||||
* - host/path
|
||||
* - flags
|
||||
* - Expiration time most significant integer
|
||||
* - Expiration time least significant integer
|
||||
* - Creation time most significant integer
|
||||
* - Creation time least significant integer
|
||||
* - Record delimiter "*"
|
||||
*
|
||||
* @note All the times are in FILETIME format.
|
||||
*/
|
||||
_parseCookieBuffer: function C__parseCookieBuffer(aTextBuffer) {
|
||||
// Note the last record is an empty string.
|
||||
let records = [r for each (r in aTextBuffer.split("*\n")) if (r)];
|
||||
for (let record of records) {
|
||||
let [name, value, hostpath, flags,
|
||||
expireTimeLo, expireTimeHi] = record.split("\n");
|
||||
|
||||
// IE stores deleted cookies with a zero-length value, skip them.
|
||||
if (value.length == 0)
|
||||
continue;
|
||||
|
||||
let hostLen = hostpath.indexOf("/");
|
||||
let host = hostpath.substr(0, hostLen);
|
||||
|
||||
// For a non-null domain, assume it's what Mozilla considers
|
||||
// a domain cookie. See bug 222343.
|
||||
if (host.length > 0) {
|
||||
// Fist delete any possible extant matching host cookie.
|
||||
Services.cookies.remove(host, name, path, false);
|
||||
// Now make it a domain cookie.
|
||||
if (host[0] != "." && !hostIsIPAddress(host))
|
||||
host = "." + host;
|
||||
}
|
||||
|
||||
let path = hostpath.substr(hostLen);
|
||||
let expireTime = CtypesHelpers.fileTimeToDate(Number(expireTimeHi),
|
||||
Number(expireTimeLo));
|
||||
Services.cookies.add(host,
|
||||
path,
|
||||
name,
|
||||
value,
|
||||
Number(flags) & 0x1, // secure
|
||||
false, // httpOnly
|
||||
false, // session
|
||||
expireTime);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function Settings() {
|
||||
}
|
||||
|
||||
Settings.prototype = {
|
||||
type: MigrationUtils.resourceTypes.SETTINGS,
|
||||
|
||||
get exists() true,
|
||||
|
||||
migrate: function S_migrate(aCallback) {
|
||||
// Converts from yes/no to a boolean.
|
||||
function yesNoToBoolean(v) v == "yes";
|
||||
|
||||
// Converts source format like "en-us,ar-kw;q=0.7,ar-om;q=0.3" into
|
||||
// destination format like "en-us, ar-kw, ar-om".
|
||||
// Final string is sorted by quality (q=) param.
|
||||
function parseAcceptLanguageList(v) {
|
||||
return v.match(/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/gi)
|
||||
.sort(function (a , b) {
|
||||
let qA = parseFloat(a.split(";q=")[1]) || 1.0;
|
||||
let qB = parseFloat(b.split(";q=")[1]) || 1.0;
|
||||
return qA < qB ? 1 : qA == qB ? 0 : -1;
|
||||
})
|
||||
.map(function(a) a.split(";")[0]);
|
||||
}
|
||||
|
||||
// For reference on some of the available IE Registry settings:
|
||||
// * http://msdn.microsoft.com/en-us/library/cc980058%28v=prot.13%29.aspx
|
||||
// * http://msdn.microsoft.com/en-us/library/cc980059%28v=prot.13%29.aspx
|
||||
|
||||
// Note that only settings exposed in our UI should be migrated.
|
||||
|
||||
this._set("Software\\Microsoft\\Internet Explorer\\International",
|
||||
"AcceptLanguage",
|
||||
"intl.accept_languages",
|
||||
parseAcceptLanguageList);
|
||||
// TODO (bug 745853): For now, only x-western font is translated.
|
||||
this._set("Software\\Microsoft\\Internet Explorer\\International\\Scripts\\3",
|
||||
"IEFixedFontName",
|
||||
"font.name.monospace.x-western");
|
||||
this._set(kMainKey,
|
||||
"Use FormSuggest",
|
||||
"browser.formfill.enable",
|
||||
yesNoToBoolean);
|
||||
this._set(kMainKey,
|
||||
"FormSuggest Passwords",
|
||||
"signon.rememberSignons",
|
||||
yesNoToBoolean);
|
||||
this._set(kMainKey,
|
||||
"Anchor Underline",
|
||||
"browser.underline_anchors",
|
||||
yesNoToBoolean);
|
||||
this._set(kMainKey,
|
||||
"Display Inline Images",
|
||||
"permissions.default.image",
|
||||
function (v) yesNoToBoolean(v) ? 1 : 2);
|
||||
this._set(kMainKey,
|
||||
"Move System Caret",
|
||||
"accessibility.browsewithcaret",
|
||||
yesNoToBoolean);
|
||||
this._set("Software\\Microsoft\\Internet Explorer\\Settings",
|
||||
"Always Use My Colors",
|
||||
"browser.display.use_document_colors",
|
||||
function (v) !Boolean(v));
|
||||
this._set("Software\\Microsoft\\Internet Explorer\\Settings",
|
||||
"Always Use My Font Face",
|
||||
"browser.display.use_document_fonts",
|
||||
function (v) !Boolean(v));
|
||||
this._set(kMainKey,
|
||||
"SmoothScroll",
|
||||
"general.smoothScroll",
|
||||
Boolean);
|
||||
this._set("Software\\Microsoft\\Internet Explorer\\TabbedBrowsing\\",
|
||||
"WarnOnClose",
|
||||
"browser.tabs.warnOnClose",
|
||||
Boolean);
|
||||
this._set("Software\\Microsoft\\Internet Explorer\\TabbedBrowsing\\",
|
||||
"OpenInForeground",
|
||||
"browser.tabs.loadInBackground",
|
||||
function (v) !Boolean(v));
|
||||
|
||||
aCallback(true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Reads a setting from the Registry and stores the converted result into
|
||||
* the appropriate Firefox preference.
|
||||
*
|
||||
* @param aPath
|
||||
* Registry path under HKCU.
|
||||
* @param aKey
|
||||
* Name of the key.
|
||||
* @param aPref
|
||||
* Firefox preference.
|
||||
* @param [optional] aTransformFn
|
||||
* Conversion function from the Registry format to the pref format.
|
||||
*/
|
||||
_set: function S__set(aPath, aKey, aPref, aTransformFn) {
|
||||
let value = readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
|
||||
aPath, aKey);
|
||||
// Don't import settings that have never been flipped.
|
||||
if (value === undefined)
|
||||
return;
|
||||
|
||||
if (aTransformFn)
|
||||
value = aTransformFn(value);
|
||||
|
||||
switch (typeof(value)) {
|
||||
case "string":
|
||||
Services.prefs.setCharPref(aPref, value);
|
||||
break;
|
||||
case "number":
|
||||
Services.prefs.setIntPref(aPref, value);
|
||||
break;
|
||||
case "boolean":
|
||||
Services.prefs.setBoolPref(aPref, value);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unexpected value type: " + typeof(value));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Migrator
|
||||
|
||||
function IEProfileMigrator()
|
||||
{
|
||||
}
|
||||
|
||||
IEProfileMigrator.prototype = Object.create(MigratorPrototype);
|
||||
|
||||
IEProfileMigrator.prototype.getResources = function IE_getResources() {
|
||||
let resources = [
|
||||
new Bookmarks()
|
||||
, new History()
|
||||
, new Cookies()
|
||||
, new Settings()
|
||||
];
|
||||
return [r for each (r in resources) if (r.exists)];
|
||||
};
|
||||
|
||||
Object.defineProperty(IEProfileMigrator.prototype, "sourceHomePageURL", {
|
||||
get: function IE_get_sourceHomePageURL() {
|
||||
let defaultStartPage = readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
|
||||
kMainKey, "Default_Page_URL");
|
||||
let startPage = readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
|
||||
kMainKey, "Start Page");
|
||||
// If the user didn't customize the Start Page, he is still on the default
|
||||
// page, that may be considered the equivalent of our about:home. There's
|
||||
// no reason to retain it, since it is heavily targeted to IE.
|
||||
let homepage = startPage != defaultStartPage ? startPage : "";
|
||||
|
||||
// IE7+ supports secondary home pages located in a REG_MULTI_SZ key. These
|
||||
// are in addition to the Start Page, and no empty entries are possible,
|
||||
// thus a Start Page is always defined if any of these exists, though it
|
||||
// may be the default one.
|
||||
let secondaryPages = readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
|
||||
kMainKey, "Secondary Start Pages");
|
||||
if (secondaryPages) {
|
||||
if (homepage)
|
||||
secondaryPages.unshift(homepage);
|
||||
homepage = secondaryPages.join("|");
|
||||
}
|
||||
|
||||
return homepage;
|
||||
}
|
||||
});
|
||||
|
||||
IEProfileMigrator.prototype.classDescription = "IE Profile Migrator";
|
||||
IEProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=ie";
|
||||
IEProfileMigrator.prototype.classID = Components.ID("{3d2532e3-4932-4774-b7ba-968f5899d3a4}");
|
||||
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([IEProfileMigrator]);
|
|
@ -55,12 +55,10 @@ EXTRA_PP_COMPONENTS = \
|
|||
$(NULL)
|
||||
|
||||
ifeq ($(OS_ARCH)_$(GNU_CXX),WINNT_)
|
||||
CPPSRCS += nsIEProfileMigrator.cpp \
|
||||
nsBrowserProfileMigratorUtils.cpp \
|
||||
nsIEHistoryEnumerator.cpp \
|
||||
$(NULL)
|
||||
CPPSRCS += nsIEHistoryEnumerator.cpp
|
||||
|
||||
EXTRA_PP_COMPONENTS += SafariProfileMigrator.js \
|
||||
EXTRA_PP_COMPONENTS += IEProfileMigrator.js \
|
||||
SafariProfileMigrator.js \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** 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 The Browser Profile Migrator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Ben Goodger.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ben Goodger <ben@bengoodger.com>
|
||||
* Asaf Romano <mozilla.mano@sent.com>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#include "nsBrowserProfileMigratorUtils.h"
|
||||
#include "nsINavBookmarksService.h"
|
||||
#include "nsBrowserCompsCID.h"
|
||||
#include "nsToolkitCompsCID.h"
|
||||
#include "nsIPlacesImportExportService.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIProperties.h"
|
||||
#include "nsIProfileMigrator.h"
|
||||
|
||||
#include "nsIURI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsIRDFService.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsXPCOMCID.h"
|
||||
|
||||
void SetUnicharPref(const char* aPref, const nsAString& aValue,
|
||||
nsIPrefBranch* aPrefs)
|
||||
{
|
||||
nsCOMPtr<nsISupportsString> supportsString =
|
||||
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
|
||||
if (supportsString) {
|
||||
supportsString->SetData(aValue);
|
||||
aPrefs->SetComplexValue(aPref, NS_GET_IID(nsISupportsString),
|
||||
supportsString);
|
||||
}
|
||||
}
|
||||
|
||||
void SetProxyPref(const nsAString& aHostPort, const char* aPref,
|
||||
const char* aPortPref, nsIPrefBranch* aPrefs)
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsCAutoString host;
|
||||
PRInt32 portValue;
|
||||
|
||||
// try parsing it as a URI first
|
||||
if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), aHostPort))
|
||||
&& NS_SUCCEEDED(uri->GetHost(host))
|
||||
&& !host.IsEmpty()
|
||||
&& NS_SUCCEEDED(uri->GetPort(&portValue))) {
|
||||
SetUnicharPref(aPref, NS_ConvertUTF8toUTF16(host), aPrefs);
|
||||
aPrefs->SetIntPref(aPortPref, portValue);
|
||||
}
|
||||
else {
|
||||
nsAutoString hostPort(aHostPort);
|
||||
PRInt32 portDelimOffset = hostPort.RFindChar(':');
|
||||
if (portDelimOffset > 0) {
|
||||
SetUnicharPref(aPref, Substring(hostPort, 0, portDelimOffset), aPrefs);
|
||||
nsAutoString port(Substring(hostPort, portDelimOffset + 1));
|
||||
nsresult stringErr;
|
||||
portValue = port.ToInteger(&stringErr);
|
||||
if (NS_SUCCEEDED(stringErr))
|
||||
aPrefs->SetIntPref(aPortPref, portValue);
|
||||
}
|
||||
else
|
||||
SetUnicharPref(aPref, hostPort, aPrefs);
|
||||
}
|
||||
}
|
||||
|
||||
void ParseOverrideServers(const nsAString& aServers, nsIPrefBranch* aBranch)
|
||||
{
|
||||
// Windows (and Opera) formats its proxy override list in the form:
|
||||
// server;server;server where server is a server name or ip address,
|
||||
// or "<local>". Mozilla's format is server,server,server, and <local>
|
||||
// must be translated to "localhost,127.0.0.1"
|
||||
nsAutoString override(aServers);
|
||||
PRInt32 left = 0, right = 0;
|
||||
for (;;) {
|
||||
right = override.FindChar(';', right);
|
||||
const nsAString& host = Substring(override, left,
|
||||
(right < 0 ? override.Length() : right) - left);
|
||||
if (host.EqualsLiteral("<local>"))
|
||||
override.Replace(left, 7, NS_LITERAL_STRING("localhost,127.0.0.1"));
|
||||
if (right < 0)
|
||||
break;
|
||||
left = right + 1;
|
||||
override.Replace(right, 1, NS_LITERAL_STRING(","));
|
||||
}
|
||||
SetUnicharPref("network.proxy.no_proxies_on", override, aBranch);
|
||||
}
|
||||
|
||||
void GetMigrateDataFromArray(MigrationData* aDataArray, PRInt32 aDataArrayLength,
|
||||
bool aReplace, nsIFile* aSourceProfile,
|
||||
PRUint16* aResult)
|
||||
{
|
||||
nsCOMPtr<nsIFile> sourceFile;
|
||||
bool exists;
|
||||
MigrationData* cursor;
|
||||
MigrationData* end = aDataArray + aDataArrayLength;
|
||||
for (cursor = aDataArray; cursor < end && cursor->fileName; ++cursor) {
|
||||
// When in replace mode, all items can be imported.
|
||||
// When in non-replace mode, only items that do not require file replacement
|
||||
// can be imported.
|
||||
if (aReplace || !cursor->replaceOnly) {
|
||||
aSourceProfile->Clone(getter_AddRefs(sourceFile));
|
||||
sourceFile->Append(nsDependentString(cursor->fileName));
|
||||
sourceFile->Exists(&exists);
|
||||
if (exists)
|
||||
*aResult |= cursor->sourceFlag;
|
||||
}
|
||||
NS_Free(cursor->fileName);
|
||||
cursor->fileName = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GetProfilePath(nsIProfileStartup* aStartup, nsCOMPtr<nsIFile>& aProfileDir)
|
||||
{
|
||||
if (aStartup) {
|
||||
aStartup->GetDirectory(getter_AddRefs(aProfileDir));
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIProperties> dirSvc
|
||||
(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
|
||||
if (dirSvc) {
|
||||
dirSvc->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
|
||||
(void**) getter_AddRefs(aProfileDir));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** 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 The Browser Profile Migrator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Ben Goodger.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ben Goodger <ben@bengoodger.com>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef browserprofilemigratorutils___h___
|
||||
#define browserprofilemigratorutils___h___
|
||||
|
||||
#define MIGRATION_ITEMBEFOREMIGRATE "Migration:ItemBeforeMigrate"
|
||||
#define MIGRATION_ITEMMIGRATEERROR "Migration:ItemError"
|
||||
#define MIGRATION_ITEMAFTERMIGRATE "Migration:ItemAfterMigrate"
|
||||
#define MIGRATION_STARTED "Migration:Started"
|
||||
#define MIGRATION_ENDED "Migration:Ended"
|
||||
|
||||
#define NOTIFY_OBSERVERS(message, item) \
|
||||
mObserverService->NotifyObservers(nsnull, message, item)
|
||||
|
||||
#define COPY_DATA(func, replace, itemIndex) \
|
||||
if ((aItems & itemIndex || !aItems)) { \
|
||||
nsAutoString index; \
|
||||
index.AppendInt(itemIndex); \
|
||||
NOTIFY_OBSERVERS(MIGRATION_ITEMBEFOREMIGRATE, index.get()); \
|
||||
if (NS_FAILED(func(replace))) \
|
||||
NOTIFY_OBSERVERS(MIGRATION_ITEMMIGRATEERROR, index.get()); \
|
||||
NOTIFY_OBSERVERS(MIGRATION_ITEMAFTERMIGRATE, index.get()); \
|
||||
}
|
||||
|
||||
#define NC_URI(property) \
|
||||
NS_LITERAL_CSTRING("http://home.netscape.com/NC-rdf#"#property)
|
||||
|
||||
#define BATCH_ACTION_HISTORY 0
|
||||
#define BATCH_ACTION_HISTORY_REPLACE 1
|
||||
#define BATCH_ACTION_BOOKMARKS 2
|
||||
#define BATCH_ACTION_BOOKMARKS_REPLACE 3
|
||||
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsStringAPI.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIProfileStartup;
|
||||
|
||||
|
||||
void SetUnicharPref(const char* aPref, const nsAString& aValue,
|
||||
nsIPrefBranch* aPrefs);
|
||||
|
||||
// Proxy utilities shared by the Opera and IE migrators
|
||||
void ParseOverrideServers(const nsAString& aServers, nsIPrefBranch* aBranch);
|
||||
void SetProxyPref(const nsAString& aHostPort, const char* aPref,
|
||||
const char* aPortPref, nsIPrefBranch* aPrefs);
|
||||
|
||||
struct MigrationData {
|
||||
PRUnichar* fileName;
|
||||
PRUint32 sourceFlag;
|
||||
bool replaceOnly;
|
||||
};
|
||||
|
||||
class nsILocalFile;
|
||||
void GetMigrateDataFromArray(MigrationData* aDataArray,
|
||||
PRInt32 aDataArrayLength,
|
||||
bool aReplace,
|
||||
nsIFile* aSourceProfile,
|
||||
PRUint16* aResult);
|
||||
|
||||
|
||||
// get the base directory of the *target* profile
|
||||
// this is already cloned, modify it to your heart's content
|
||||
void GetProfilePath(nsIProfileStartup* aStartup, nsCOMPtr<nsIFile>& aProfileDir);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,208 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** 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 mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
/* Private header describing the class to migrate preferences from
|
||||
Windows Trident to Gecko. This is a virtual class. */
|
||||
|
||||
#ifndef ieprofilemigrator___h___
|
||||
#define ieprofilemigrator___h___
|
||||
|
||||
#include <time.h>
|
||||
#include <windows.h>
|
||||
#include <ole2.h>
|
||||
#include "nsIBrowserProfileMigrator.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsINavHistoryService.h"
|
||||
|
||||
class nsIFile;
|
||||
class nsICookieManager2;
|
||||
class nsIRDFResource;
|
||||
class nsINavBookmarksService;
|
||||
class nsIPrefBranch;
|
||||
|
||||
struct SignonData {
|
||||
PRUnichar* user;
|
||||
PRUnichar* pass;
|
||||
char* realm;
|
||||
};
|
||||
|
||||
// VC11 doesn't ship with pstore.h, so we go ahead and define the stuff that
|
||||
// we need from that file here.
|
||||
class IEnumPStoreItems : public IUnknown {
|
||||
public:
|
||||
virtual HRESULT STDMETHODCALLTYPE Next(DWORD celt, LPWSTR* rgelt,
|
||||
DWORD* pceltFetched) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE Skip(DWORD celt) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE Reset() = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE Clone(IEnumPStoreItems** ppenum) = 0;
|
||||
};
|
||||
|
||||
class IEnumPStoreTypes; // not used
|
||||
struct PST_PROVIDERINFO; // not used
|
||||
struct PST_TYPEINFO; // not used
|
||||
struct PST_PROMPTINFO; // not used
|
||||
struct PST_ACCESSRULESET; // not used
|
||||
typedef DWORD PST_KEY;
|
||||
typedef DWORD PST_ACCESSMODE;
|
||||
|
||||
class IPStore : public IUnknown {
|
||||
public:
|
||||
virtual HRESULT STDMETHODCALLTYPE GetInfo(PST_PROVIDERINFO** ppProperties) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE GetProvParam(DWORD dwParam, DWORD* pcbData,
|
||||
BYTE** ppbData, DWORD dwFlags) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE SetProvParam(DWORD dwParam, DWORD cbData,
|
||||
BYTE* pbData, DWORD dwFlags) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE CreateType(PST_KEY Key, const GUID* pType,
|
||||
PST_TYPEINFO* pInfo, DWORD dwFlags) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(PST_KEY Key, const GUID* pType,
|
||||
PST_TYPEINFO** ppInfo, DWORD dwFlags) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE DeleteType(PST_KEY Key, const GUID* pType,
|
||||
DWORD dwFlags) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE CreateSubtype(PST_KEY Key, const GUID* pType,
|
||||
const GUID* pSubtype, PST_TYPEINFO* pInfo,
|
||||
PST_ACCESSRULESET* pRules, DWORD dwFlags) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE GetSubtypeInfo(PST_KEY Key, const GUID* pType,
|
||||
const GUID* pSubtype, PST_TYPEINFO** ppInfo,
|
||||
DWORD dwFlags) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE DeleteSubtype(PST_KEY Key, const GUID* pType,
|
||||
const GUID* pSubtype, DWORD dwFlags) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE ReadAccessRuleset(PST_KEY Key, const GUID* pType,
|
||||
const GUID* pSubtype, PST_ACCESSRULESET** ppRules,
|
||||
DWORD dwFlags) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE WriteAccessRuleset(PST_KEY Key, const GUID* pType,
|
||||
const GUID* pSubtype, PST_ACCESSRULESET* pRules,
|
||||
DWORD dwFlags) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE EnumTypes(PST_KEY Key, DWORD dwFlags, IEnumPStoreTypes** ppenum) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE EnumSubtypes(PST_KEY Key, const GUID* pType,
|
||||
DWORD dwFlags, IEnumPStoreTypes** ppenum) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE DeleteItem(PST_KEY Key, const GUID* pItemType,
|
||||
const GUID* pItemSubtype, LPCWSTR szItemName,
|
||||
PST_PROMPTINFO* pPromptInfo, DWORD dwFlags) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE ReadItem(PST_KEY Key, const GUID* pItemType,
|
||||
const GUID* pItemSubtype, LPCWSTR szItemName,
|
||||
DWORD* pcbData, BYTE** ppbData,
|
||||
PST_PROMPTINFO* pPromptInfo, DWORD dwFlags) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE WriteItem(PST_KEY Key, const GUID* pItemType,
|
||||
const GUID* pItemSubtype, LPCWSTR szItemName,
|
||||
DWORD cbData, BYTE* pbData,
|
||||
PST_PROMPTINFO* pPromptInfo, DWORD dwFlags) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE OpenItem(PST_KEY Key, const GUID* pItemType,
|
||||
const GUID* pItemSubtype, LPCWSTR szItemName,
|
||||
PST_ACCESSMODE ModeFlags, PST_PROMPTINFO* pPromptInfo,
|
||||
DWORD dwFlags) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE CloseItem(PST_KEY Key, const GUID* pItemType,
|
||||
const GUID* pItemSubtype, LPCWSTR szItemName,
|
||||
DWORD dwFlags) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE EnumItems(PST_KEY Key, const GUID* pItemType,
|
||||
const GUID* pItemSubtype, DWORD dwFlags,
|
||||
IEnumPStoreItems** ppenum) = 0;
|
||||
};
|
||||
|
||||
|
||||
class nsIEProfileMigrator : public nsIBrowserProfileMigrator,
|
||||
public nsINavHistoryBatchCallback {
|
||||
public:
|
||||
NS_DECL_NSIBROWSERPROFILEMIGRATOR
|
||||
NS_DECL_NSINAVHISTORYBATCHCALLBACK
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsIEProfileMigrator();
|
||||
virtual ~nsIEProfileMigrator();
|
||||
|
||||
protected:
|
||||
nsresult CopyPreferences(bool aReplace);
|
||||
nsresult CopyStyleSheet(bool aReplace);
|
||||
nsresult CopyCookies(bool aReplace);
|
||||
nsresult CopyProxyPreferences(nsIPrefBranch* aPrefs);
|
||||
nsresult CopySecurityPrefs(nsIPrefBranch* aPrefs);
|
||||
/**
|
||||
* Migrate history to Places.
|
||||
* This will end up calling CopyHistoryBatched helper, that provides batch
|
||||
* support. Batching allows for better performances and integrity.
|
||||
*
|
||||
* @param aReplace
|
||||
* Indicates if we should replace current history or append to it.
|
||||
*/
|
||||
nsresult CopyHistory(bool aReplace);
|
||||
nsresult CopyHistoryBatched(bool aReplace);
|
||||
|
||||
bool KeyIsURI(const nsAString& aKey, char** aRealm);
|
||||
|
||||
nsresult CopyPasswords(bool aReplace);
|
||||
nsresult MigrateSiteAuthSignons(IPStore* aPStore);
|
||||
nsresult GetSignonsListFromPStore(IPStore* aPStore, nsTArray<SignonData>* aSignonsFound);
|
||||
nsresult ResolveAndMigrateSignons(IPStore* aPStore, nsTArray<SignonData>* aSignonsFound);
|
||||
void EnumerateUsernames(const nsAString& aKey, PRUnichar* aData, unsigned long aCount, nsTArray<SignonData>* aSignonsFound);
|
||||
void GetUserNameAndPass(unsigned char* data, unsigned long len, unsigned char** username, unsigned char** pass);
|
||||
|
||||
nsresult CopyFormData(bool aReplace);
|
||||
nsresult AddDataToFormHistory(const nsAString& aKey, PRUnichar* data, unsigned long len);
|
||||
/**
|
||||
* Migrate bookmarks to Places.
|
||||
* This will end up calling CopyFavoritesBatched helper, that provides batch
|
||||
* support. Batching allows for better performances and integrity.
|
||||
*
|
||||
* @param aReplace
|
||||
* Indicates if we should replace current bookmarks or append to them.
|
||||
* When appending we will usually default to bookmarks menu.
|
||||
*/
|
||||
nsresult CopyFavorites(bool aReplace);
|
||||
nsresult CopyFavoritesBatched(bool aReplace);
|
||||
void ResolveShortcut(const nsString &aFileName, char** aOutURL);
|
||||
nsresult ParseFavoritesFolder(nsIFile* aDirectory,
|
||||
PRInt64 aParentFolder,
|
||||
nsINavBookmarksService* aBookmarksService,
|
||||
const nsAString& aPersonalToolbarFolderName,
|
||||
bool aIsAtRootLevel);
|
||||
nsresult CopySmartKeywords(nsINavBookmarksService* aBMS,
|
||||
PRInt64 aParentFolder);
|
||||
|
||||
nsresult CopyCookiesFromBuffer(char *aBuffer, PRUint32 aBufferLength,
|
||||
nsICookieManager2 *aCookieManager);
|
||||
void DelimitField(char **aBuffer, const char *aBufferEnd, char **aField);
|
||||
time_t FileTimeToTimeT(const char *aLowDateIntString,
|
||||
const char *aHighDateIntString);
|
||||
void GetUserStyleSheetFile(nsIFile **aUserFile);
|
||||
bool TestForIE7();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIObserverService> mObserverService;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -3,4 +3,4 @@ head = head_migration.js
|
|||
tail =
|
||||
|
||||
[test_IE_bookmarks.js]
|
||||
skip-if = os != "win"
|
||||
skip-if = true
|
||||
|
|
|
@ -38,6 +38,10 @@
|
|||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
|
||||
"resource:///modules/DownloadsCommon.jsm");
|
||||
|
||||
var gMainPane = {
|
||||
_pane: null,
|
||||
|
||||
|
@ -55,12 +59,25 @@ var gMainPane = {
|
|||
this.updateBrowserStartupLastSession();
|
||||
this.startupPagePrefChanged();
|
||||
|
||||
this.setupDownloadsWindowOptions();
|
||||
|
||||
// Notify observers that the UI is now ready
|
||||
Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService)
|
||||
.notifyObservers(window, "main-pane-loaded", null);
|
||||
},
|
||||
|
||||
setupDownloadsWindowOptions: function ()
|
||||
{
|
||||
var showWhenDownloading = document.getElementById("showWhenDownloading");
|
||||
var closeWhenDone = document.getElementById("closeWhenDone");
|
||||
|
||||
// These radio-buttons should not be visible if we have enabled the Downloads Panel.
|
||||
let shouldHide = !DownloadsCommon.useToolkitUI;
|
||||
showWhenDownloading.hidden = shouldHide;
|
||||
closeWhenDone.hidden = shouldHide;
|
||||
},
|
||||
|
||||
// HOME PAGE
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,4 +1,17 @@
|
|||
# WebappRT doesn't need these instructions, and they don't necessarily work
|
||||
# with it, but it does use a GRE directory that the GRE shares with Firefox,
|
||||
# so in order to prevent the instructions from being processed for WebappRT,
|
||||
# we need to restrict them to the applications that depend on them, i.e.:
|
||||
#
|
||||
# b2g: {3c2e2abc-06d4-11e1-ac3b-374f68613e61}
|
||||
# browser: {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
|
||||
# mobile/android: {aa3c5121-dab2-40e2-81ca-7ea25febc110}
|
||||
# mobile/xul: {a23983c0-fd0e-11dc-95ff-0800200c9a66}
|
||||
#
|
||||
# In theory we should do this for all these instructions, but in practice it is
|
||||
# sufficient to do it for the app-startup one, and the file is simpler that way.
|
||||
|
||||
component {c31f4883-839b-45f6-82ad-a6a9bc5ad599} nsPrivateBrowsingService.js
|
||||
contract @mozilla.org/privatebrowsing;1 {c31f4883-839b-45f6-82ad-a6a9bc5ad599}
|
||||
category command-line-handler m-privatebrowsing @mozilla.org/privatebrowsing;1
|
||||
category app-startup nsPrivateBrowsingService service,@mozilla.org/privatebrowsing;1
|
||||
category app-startup nsPrivateBrowsingService service,@mozilla.org/privatebrowsing;1 application={3c2e2abc-06d4-11e1-ac3b-374f68613e61} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} application={aa3c5121-dab2-40e2-81ca-7ea25febc110} application={a23983c0-fd0e-11dc-95ff-0800200c9a66}
|
||||
|
|
|
@ -1,5 +1,18 @@
|
|||
# WebappRT doesn't need these instructions, and they don't necessarily work
|
||||
# with it, but it does use a GRE directory that the GRE shares with Firefox,
|
||||
# so in order to prevent the instructions from being processed for WebappRT,
|
||||
# we need to restrict them to the applications that depend on them, i.e.:
|
||||
#
|
||||
# b2g: {3c2e2abc-06d4-11e1-ac3b-374f68613e61}
|
||||
# browser: {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
|
||||
# mobile/android: {aa3c5121-dab2-40e2-81ca-7ea25febc110}
|
||||
# mobile/xul: {a23983c0-fd0e-11dc-95ff-0800200c9a66}
|
||||
#
|
||||
# In theory we should do this for all these instructions, but in practice it is
|
||||
# sufficient to do it for the app-startup one, and the file is simpler that way.
|
||||
|
||||
component {5280606b-2510-4fe0-97ef-9b5a22eafe6b} nsSessionStore.js
|
||||
contract @mozilla.org/browser/sessionstore;1 {5280606b-2510-4fe0-97ef-9b5a22eafe6b}
|
||||
component {ec7a6c20-e081-11da-8ad9-0800200c9a66} nsSessionStartup.js
|
||||
contract @mozilla.org/browser/sessionstartup;1 {ec7a6c20-e081-11da-8ad9-0800200c9a66}
|
||||
category app-startup nsSessionStartup service,@mozilla.org/browser/sessionstartup;1
|
||||
category app-startup nsSessionStartup service,@mozilla.org/browser/sessionstartup;1 application={3c2e2abc-06d4-11e1-ac3b-374f68613e61} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} application={aa3c5121-dab2-40e2-81ca-7ea25febc110} application={a23983c0-fd0e-11dc-95ff-0800200c9a66}
|
||||
|
|
|
@ -30,8 +30,6 @@ let TestObserver = {
|
|||
"sourceName is correct");
|
||||
|
||||
if (++errors == 2) {
|
||||
is(lastWindowId, aSubject.outerWindowID,
|
||||
"same window ID (" + lastWindowId + ") for both errors");
|
||||
executeSoon(performTest);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -308,6 +308,9 @@
|
|||
@BINPATH@/components/nsBrowserGlue.js
|
||||
@BINPATH@/components/nsSetDefaultBrowser.manifest
|
||||
@BINPATH@/components/nsSetDefaultBrowser.js
|
||||
@BINPATH@/components/BrowserDownloads.manifest
|
||||
@BINPATH@/components/DownloadsStartup.js
|
||||
@BINPATH@/components/DownloadsUI.js
|
||||
@BINPATH@/components/BrowserPlaces.manifest
|
||||
@BINPATH@/components/BrowserPageThumbs.manifest
|
||||
@BINPATH@/components/nsPrivateBrowsingService.manifest
|
||||
|
@ -409,6 +412,7 @@
|
|||
@BINPATH@/components/ChromeProfileMigrator.js
|
||||
@BINPATH@/components/FirefoxProfileMigrator.js
|
||||
#ifdef XP_WIN
|
||||
@BINPATH@/components/IEProfileMigrator.js
|
||||
@BINPATH@/components/SafariProfileMigrator.js
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
|
@ -499,6 +503,9 @@
|
|||
#ifdef MOZ_SERVICES_SYNC
|
||||
@BINPATH@/@PREF_DIR@/services-sync.js
|
||||
#endif
|
||||
#ifdef MOZ_WEBAPP_RUNTIME
|
||||
@BINPATH@/@PREF_DIR@/webapprt@mozilla.org/prefs.js
|
||||
#endif
|
||||
@BINPATH@/greprefs.js
|
||||
@BINPATH@/defaults/autoconfig/platform.js
|
||||
@BINPATH@/defaults/autoconfig/prefcalls.js
|
||||
|
@ -620,3 +627,14 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
|
|||
@BINPATH@/*.xqs
|
||||
@BINPATH@/components/*.xqs
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WEBAPP_RUNTIME
|
||||
; [Webapp Runtime]
|
||||
@BINPATH@/webapprt-stub@BIN_SUFFIX@
|
||||
@BINPATH@/chrome/webapprt@JAREXT@
|
||||
@BINPATH@/chrome/webapprt.manifest
|
||||
@BINPATH@/components/WebappRTComponents.manifest
|
||||
@BINPATH@/components/WebappRTDirectoryProvider.js
|
||||
@BINPATH@/components/WebappRTCommandLineHandler.js
|
||||
@BINPATH@/webapprt.ini
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
- You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!-- LOCALIZATION NOTE (indicator.tooltiptext):
|
||||
Tooltip for the indicator that displays the progress of ongoing downloads.
|
||||
-->
|
||||
<!ENTITY indicator.tooltiptext "Downloads">
|
||||
|
||||
<!-- LOCALIZATION NOTE (downloads.title):
|
||||
Used by screen readers to describe the Downloads Panel.
|
||||
-->
|
||||
<!ENTITY downloads.title "Downloads">
|
||||
|
||||
<!ENTITY cmd.pause.label "Pause">
|
||||
<!ENTITY cmd.pause.accesskey "P">
|
||||
<!ENTITY cmd.resume.label "Resume">
|
||||
<!ENTITY cmd.resume.accesskey "R">
|
||||
<!ENTITY cmd.cancel.label "Cancel">
|
||||
<!ENTITY cmd.cancel.accesskey "C">
|
||||
<!-- LOCALIZATION NOTE (cmd.show.label, cmd.show.accesskey, cmd.showMac.label,
|
||||
cmd.showMac.accesskey):
|
||||
The show and showMac commands are never shown together, thus they can share
|
||||
the same access key (though the two access keys can also be different).
|
||||
-->
|
||||
<!ENTITY cmd.show.label "Open Containing Folder">
|
||||
<!ENTITY cmd.show.accesskey "F">
|
||||
<!ENTITY cmd.showMac.label "Show In Finder">
|
||||
<!ENTITY cmd.showMac.accesskey "F">
|
||||
<!ENTITY cmd.retry.label "Retry">
|
||||
<!ENTITY cmd.goToDownloadPage.label "Go To Download Page">
|
||||
<!ENTITY cmd.goToDownloadPage.accesskey "G">
|
||||
<!ENTITY cmd.copyDownloadLink.label "Copy Download Link">
|
||||
<!ENTITY cmd.copyDownloadLink.accesskey "L">
|
||||
<!ENTITY cmd.removeFromList.label "Remove From List">
|
||||
<!ENTITY cmd.removeFromList.accesskey "e">
|
||||
<!ENTITY cmd.clearList.label "Clear List">
|
||||
<!ENTITY cmd.clearList.accesskey "a">
|
||||
|
||||
<!ENTITY downloadshistory.label "Show All Downloads">
|
||||
<!ENTITY downloadshistory.accesskey "S">
|
|
@ -0,0 +1,72 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# LOCALIZATION NOTE (stateStarting):
|
||||
# Indicates that the download is starting.
|
||||
stateStarting=Starting…
|
||||
# LOCALIZATION NOTE (stateScanning):
|
||||
# Indicates that an external program is scanning the download for viruses.
|
||||
stateScanning=Scanning for viruses…
|
||||
# LOCALIZATION NOTE (stateFailed):
|
||||
# Indicates that the download failed because of an error.
|
||||
stateFailed=Failed
|
||||
# LOCALIZATION NOTE (statePaused):
|
||||
# Indicates that the download was paused by the user.
|
||||
statePaused=Paused
|
||||
# LOCALIZATION NOTE (stateCanceled):
|
||||
# Indicates that the download was canceled by the user.
|
||||
stateCanceled=Canceled
|
||||
# LOCALIZATION NOTE (stateBlockedParentalControls):
|
||||
# Indicates that the download was blocked by the Parental Controls feature of
|
||||
# Windows. "Parental Controls" should be consistently named and capitalized
|
||||
# with the display of this feature in Windows. The following article can
|
||||
# provide a reference for the translation of "Parental Controls" in various
|
||||
# languages:
|
||||
# http://windows.microsoft.com/en-US/windows-vista/Set-up-Parental-Controls
|
||||
stateBlockedParentalControls=Blocked by Parental Controls
|
||||
# LOCALIZATION NOTE (stateBlockedPolicy):
|
||||
# Indicates that the download was blocked on Windows because of the "Launching
|
||||
# applications and unsafe files" setting of the "security zone" associated with
|
||||
# the target site. "Security zone" should be consistently named and capitalized
|
||||
# with the display of this feature in Windows. The following article can
|
||||
# provide a reference for the translation of "security zone" in various
|
||||
# languages:
|
||||
# http://support.microsoft.com/kb/174360
|
||||
stateBlockedPolicy=Blocked by your security zone policy
|
||||
# LOCALIZATION NOTE (stateDirty):
|
||||
# Indicates that the download was blocked after scanning.
|
||||
stateDirty=Blocked: May contain a virus or spyware
|
||||
|
||||
# LOCALIZATION NOTE (sizeWithUnits):
|
||||
# %1$S is replaced with the size number, and %2$S with the measurement unit.
|
||||
sizeWithUnits=%1$S %2$S
|
||||
sizeUnknown=Unknown size
|
||||
|
||||
# LOCALIZATION NOTE (shortTimeLeftSeconds, shortTimeLeftMinutes,
|
||||
# shortTimeLeftHours, shortTimeLeftDays):
|
||||
# These values are displayed in the downloads indicator in the main browser
|
||||
# window, where space is available for three characters maximum. %1$S is
|
||||
# replaced with the time left for the given measurement unit. Even for days,
|
||||
# the value is never longer than two digits.
|
||||
shortTimeLeftSeconds=%1$Ss
|
||||
shortTimeLeftMinutes=%1$Sm
|
||||
shortTimeLeftHours=%1$Sh
|
||||
shortTimeLeftDays=%1$Sd
|
||||
|
||||
# LOCALIZATION NOTE (statusSeparator, statusSeparatorBeforeNumber):
|
||||
# These strings define templates for the separation of different elements in the
|
||||
# status line of a download item. As a separator, by default we use the Unicode
|
||||
# character U+2014 'EM DASH' (long dash). Examples of status lines include
|
||||
# "Canceled - 222.net", "1.1 MB - website2.com", or "Paused - 1.1 MB". Note
|
||||
# that we use a wider space after the separator when it is followed by a number,
|
||||
# just to avoid visually confusing it with with a minus sign with some fonts.
|
||||
# If you use a different separator, this might not be necessary. However, there
|
||||
# is usually no need to change the separator or the order of the substitutions,
|
||||
# even for right-to-left languages, unless the defaults are not suitable.
|
||||
statusSeparator=%1$S \u2014 %2$S
|
||||
statusSeparatorBeforeNumber=%1$S \u2014 %2$S
|
||||
|
||||
fileExecutableSecurityWarning="%S" is an executable file. Executable files may contain viruses or other malicious code that could harm your computer. Use caution when opening this file. Are you sure you want to launch "%S"?
|
||||
fileExecutableSecurityWarningTitle=Open Executable File?
|
||||
fileExecutableSecurityWarningDontAsk=Don't ask me this again
|
|
@ -7,9 +7,6 @@ sourceNameChrome=Google Chrome
|
|||
sourceNameFirefox=Mozilla Firefox
|
||||
|
||||
importedBookmarksFolder=From %S
|
||||
importedSearchURLsFolder=Keyword Searches (From %S)
|
||||
importedSearchURLsTitle=Search on %S
|
||||
importedSearchUrlDesc=Type "%S <search query>" in the Location Bar to perform a search on %S.
|
||||
|
||||
importedSafariReadingList=Reading List (From Safari)
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
- You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!-- LOCALIZATION NOTE: These are localized strings for the webapp runtime,
|
||||
- which loads a webapp in a separate process from Firefox. Webapps loaded
|
||||
- in this way have very little application chrome, but the runtime does
|
||||
- provide them with some default functionality, like the standard OS
|
||||
- menus/menuitems. -->
|
||||
|
||||
<!ENTITY fileMenu.label "File">
|
||||
<!ENTITY fileMenu.accesskey "F">
|
||||
|
||||
<!ENTITY quitApplicationCmdWin.label "Exit">
|
||||
<!ENTITY quitApplicationCmdWin.accesskey "x">
|
||||
<!ENTITY quitApplicationCmd.label "Quit">
|
||||
<!ENTITY quitApplicationCmd.accesskey "Q">
|
||||
<!-- On Mac, we create the Quit and Hide command labels dynamically,
|
||||
- using properties in window.properties, in order to include the name
|
||||
- of the webapp in the labels without creating a DTD file for it. -->
|
||||
<!ENTITY quitApplicationCmdMac.key "Q">
|
||||
<!ENTITY hideThisAppCmdMac.key "H">
|
||||
<!ENTITY hideOtherAppsCmdMac.label "Hide Others">
|
||||
<!ENTITY hideOtherAppsCmdMac.key "H">
|
||||
<!ENTITY showAllAppsCmdMac.label "Show All">
|
||||
|
||||
<!ENTITY editMenu.label "Edit">
|
||||
<!ENTITY editMenu.accesskey "E">
|
||||
<!ENTITY undoCmd.label "Undo">
|
||||
<!ENTITY undoCmd.key "Z">
|
||||
<!ENTITY undoCmd.accesskey "U">
|
||||
<!ENTITY redoCmd.label "Redo">
|
||||
<!ENTITY redoCmd.key "Y">
|
||||
<!ENTITY redoCmd.accesskey "R">
|
||||
<!ENTITY cutCmd.label "Cut">
|
||||
<!ENTITY cutCmd.key "X">
|
||||
<!ENTITY cutCmd.accesskey "t">
|
||||
<!ENTITY copyCmd.label "Copy">
|
||||
<!ENTITY copyCmd.key "C">
|
||||
<!ENTITY copyCmd.accesskey "C">
|
||||
<!ENTITY pasteCmd.label "Paste">
|
||||
<!ENTITY pasteCmd.key "V">
|
||||
<!ENTITY pasteCmd.accesskey "P">
|
||||
<!ENTITY deleteCmd.label "Delete">
|
||||
<!ENTITY deleteCmd.key "D">
|
||||
<!ENTITY deleteCmd.accesskey "D">
|
||||
<!ENTITY selectAllCmd.label "Select All">
|
||||
<!ENTITY selectAllCmd.key "A">
|
||||
<!ENTITY selectAllCmd.accesskey "A">
|
|
@ -0,0 +1,17 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# LOCALIZATION NOTE: These are localized strings for the webapp runtime,
|
||||
# which loads a webapp in a separate process from Firefox. Webapps loaded
|
||||
# in this way have very little application chrome, but the runtime does
|
||||
# provide them with some default functionality, like the standard OS
|
||||
# menus/menuitems.
|
||||
|
||||
# LOCALIZATION NOTE (quitApplicationCmdMac.label): %S will be replaced with
|
||||
# the name of the webapp.
|
||||
quitApplicationCmdMac.label=Quit %S
|
||||
|
||||
# LOCALIZATION NOTE (hideApplicationCmdMac.label): %S will be replaced with
|
||||
# the name of the webapp.
|
||||
hideApplicationCmdMac.label=Hide %S
|
|
@ -50,6 +50,8 @@
|
|||
locale/browser/tabbrowser.properties (%chrome/browser/tabbrowser.properties)
|
||||
locale/browser/tabview.properties (%chrome/browser/tabview.properties)
|
||||
locale/browser/taskbar.properties (%chrome/browser/taskbar.properties)
|
||||
locale/browser/downloads/downloads.dtd (%chrome/browser/downloads/downloads.dtd)
|
||||
locale/browser/downloads/downloads.properties (%chrome/browser/downloads/downloads.properties)
|
||||
locale/browser/places/places.dtd (%chrome/browser/places/places.dtd)
|
||||
locale/browser/places/places.properties (%chrome/browser/places/places.properties)
|
||||
locale/browser/places/editBookmarkOverlay.dtd (%chrome/browser/places/editBookmarkOverlay.dtd)
|
||||
|
@ -108,3 +110,6 @@
|
|||
% locale testpilot @AB_CD@ %locale/feedback/
|
||||
locale/feedback/main.dtd (%feedback/main.dtd)
|
||||
locale/feedback/main.properties (%feedback/main.properties)
|
||||
% locale webapprt @AB_CD@ %locale/webapprt/
|
||||
locale/webapprt/webapp.dtd (%webapprt/webapp.dtd)
|
||||
locale/webapprt/webapp.properties (%webapprt/webapp.properties)
|
||||
|
|
|
@ -48,6 +48,8 @@ browser/components/about/Makefile
|
|||
browser/components/build/Makefile
|
||||
browser/components/certerror/Makefile
|
||||
browser/components/dirprovider/Makefile
|
||||
browser/components/downloads/Makefile
|
||||
browser/components/downloads/src/Makefile
|
||||
browser/components/feeds/Makefile
|
||||
browser/components/feeds/public/Makefile
|
||||
browser/components/feeds/src/Makefile
|
||||
|
@ -131,6 +133,8 @@ if [ "$ENABLE_TESTS" ]; then
|
|||
browser/base/content/test/newtab/Makefile
|
||||
browser/components/certerror/test/Makefile
|
||||
browser/components/dirprovider/tests/Makefile
|
||||
browser/components/downloads/test/Makefile
|
||||
browser/components/downloads/test/browser/Makefile
|
||||
browser/components/preferences/tests/Makefile
|
||||
browser/components/search/test/Makefile
|
||||
browser/components/sessionstore/test/Makefile
|
||||
|
|
|
@ -62,4 +62,8 @@ EXTRA_JS_MODULES += \
|
|||
$(NULL)
|
||||
endif
|
||||
|
||||
EXTRA_PP_JS_MODULES = \
|
||||
WebappsInstaller.jsm \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* This function receives a list of icon sizes
|
||||
* and URLs and returns the url string for the biggest icon.
|
||||
*
|
||||
* @param aIcons An object where the keys are the icon sizes
|
||||
* and the values are URL strings. E.g.:
|
||||
* aIcons = {
|
||||
* "16": "http://www.example.org/icon16.png",
|
||||
* "32": "http://www.example.org/icon32.png"
|
||||
* };
|
||||
*
|
||||
* @returns the URL string for the largest specified icon
|
||||
*/
|
||||
function getBiggestIconURL(aIcons) {
|
||||
let iconSizes = Object.keys(aIcons);
|
||||
if (iconSizes.length == 0) {
|
||||
return "";
|
||||
}
|
||||
iconSizes.sort(function(a, b) a - b);
|
||||
return aIcons[iconSizes.pop()];
|
||||
}
|
||||
|
||||
/**
|
||||
* This function retrieves the icon for an app as specified
|
||||
* in the iconURI on the shell object.
|
||||
* Upon completion it will call aShell.processIcon()
|
||||
*
|
||||
* @param aShell The shell that specifies the properties
|
||||
* of the native app. Three properties from this
|
||||
* shell will be used in this function:
|
||||
* - iconURI
|
||||
* - useTmpForIcon
|
||||
* - processIcon()
|
||||
*/
|
||||
function getIconForApp(aShell, callback) {
|
||||
let iconURI = aShell.iconURI;
|
||||
let mimeService = Cc["@mozilla.org/mime;1"]
|
||||
.getService(Ci.nsIMIMEService);
|
||||
|
||||
let mimeType;
|
||||
try {
|
||||
let tIndex = iconURI.path.indexOf(";");
|
||||
if("data" == iconURI.scheme && tIndex != -1) {
|
||||
mimeType = iconURI.path.substring(0, tIndex);
|
||||
} else {
|
||||
mimeType = mimeService.getTypeFromURI(iconURI);
|
||||
}
|
||||
} catch(e) {
|
||||
throw("getIconFromURI - Failed to determine MIME type");
|
||||
}
|
||||
|
||||
try {
|
||||
let listener;
|
||||
if(aShell.useTmpForIcon) {
|
||||
let downloadObserver = {
|
||||
onDownloadComplete: function(downloader, request, cx, aStatus, file) {
|
||||
// pass downloader just to keep reference around
|
||||
onIconDownloaded(aShell, mimeType, aStatus, file, callback, downloader);
|
||||
}
|
||||
};
|
||||
|
||||
tmpIcon = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
tmpIcon.append("tmpicon." + mimeService.getPrimaryExtension(mimeType, ""));
|
||||
tmpIcon.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
|
||||
|
||||
listener = Cc["@mozilla.org/network/downloader;1"]
|
||||
.createInstance(Ci.nsIDownloader);
|
||||
listener.init(downloadObserver, tmpIcon);
|
||||
} else {
|
||||
let pipe = Cc["@mozilla.org/pipe;1"]
|
||||
.createInstance(Ci.nsIPipe);
|
||||
pipe.init(true, true, 0, 0xffffffff, null);
|
||||
|
||||
listener = Cc["@mozilla.org/network/simple-stream-listener;1"]
|
||||
.createInstance(Ci.nsISimpleStreamListener);
|
||||
listener.init(pipe.outputStream, {
|
||||
onStartRequest: function() {},
|
||||
onStopRequest: function(aRequest, aContext, aStatusCode) {
|
||||
pipe.outputStream.close();
|
||||
onIconDownloaded(aShell, mimeType, aStatusCode, pipe.inputStream, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let channel = NetUtil.newChannel(iconURI);
|
||||
let CertUtils = { };
|
||||
Cu.import("resource://gre/modules/CertUtils.jsm", CertUtils);
|
||||
// Pass true to avoid optional redirect-cert-checking behavior.
|
||||
channel.notificationCallbacks = new CertUtils.BadCertHandler(true);
|
||||
|
||||
channel.asyncOpen(listener, null);
|
||||
} catch(e) {
|
||||
throw("getIconFromURI - Failure getting icon (" + e + ")");
|
||||
}
|
||||
}
|
||||
|
||||
function onIconDownloaded(aShell, aMimeType, aStatusCode, aIcon, aCallback) {
|
||||
if (Components.isSuccessCode(aStatusCode)) {
|
||||
aShell.processIcon(aMimeType, aIcon, aCallback);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,358 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
let EXPORTED_SYMBOLS = ["WebappsInstaller"];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource:///modules/Services.jsm");
|
||||
Cu.import("resource:///modules/FileUtils.jsm");
|
||||
Cu.import("resource:///modules/NetUtil.jsm");
|
||||
|
||||
let WebappsInstaller = {
|
||||
/**
|
||||
* Creates a native installation of the web app in the OS
|
||||
*
|
||||
* @param aData the manifest data provided by the web app
|
||||
*
|
||||
* @returns bool true on success, false if an error was thrown
|
||||
*/
|
||||
install: function(aData) {
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
let shell = new MacNativeApp(aData);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
||||
try {
|
||||
shell.install();
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error installing app: " + ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function implements the common constructor for both
|
||||
* the Windows and Mac native app shells. It reads and parses
|
||||
* the data from the app manifest and stores it in the NativeApp
|
||||
* object. It's meant to be called as NativeApp.call(this, aData)
|
||||
* from the platform-specific constructor.
|
||||
*
|
||||
* @param aData the data object provided by the web app with
|
||||
* all the app settings and specifications.
|
||||
*
|
||||
*/
|
||||
function NativeApp(aData) {
|
||||
let app = this.app = aData.app;
|
||||
|
||||
let origin = Services.io.newURI(app.origin, null, null);
|
||||
|
||||
if (app.manifest.launch_path) {
|
||||
this.launchURI = Services.io.newURI(origin.resolve(app.manifest.launch_path),
|
||||
null, null);
|
||||
} else {
|
||||
this.launchURI = origin.clone();
|
||||
}
|
||||
|
||||
let biggestIcon = getBiggestIconURL(app.manifest.icons);
|
||||
try {
|
||||
let iconURI = Services.io.newURI(biggestIcon, null, null);
|
||||
if (iconURI.scheme == "data") {
|
||||
this.iconURI = iconURI;
|
||||
}
|
||||
} catch (ex) {}
|
||||
|
||||
if (!this.iconURI) {
|
||||
try {
|
||||
this.iconURI = Services.io.newURI(origin.resolve(biggestIcon), null, null);
|
||||
}
|
||||
catch (ex) {}
|
||||
}
|
||||
|
||||
this.appName = sanitize(app.manifest.name);
|
||||
this.appNameAsFilename = stripStringForFilename(this.appName);
|
||||
|
||||
if(app.manifest.developer && app.manifest.developer.name) {
|
||||
let devName = app.manifest.developer.name.substr(0, 128);
|
||||
devName = sanitize(devName);
|
||||
if (devName) {
|
||||
this.developerName = devName;
|
||||
}
|
||||
}
|
||||
|
||||
let shortDesc = this.appName;
|
||||
if (app.manifest.description) {
|
||||
let firstLine = app.manifest.description.split("\n")[0];
|
||||
shortDesc = firstLine.length <= 256
|
||||
? firstLine
|
||||
: firstLine.substr(0, 253) + "...";
|
||||
}
|
||||
this.shortDescription = sanitize(shortDesc);
|
||||
|
||||
this.manifest = app.manifest;
|
||||
|
||||
this.profileFolder = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
|
||||
function MacNativeApp(aData) {
|
||||
NativeApp.call(this, aData);
|
||||
this._init();
|
||||
}
|
||||
|
||||
MacNativeApp.prototype = {
|
||||
_init: function() {
|
||||
this.appSupportDir = Services.dirsvc.get("ULibDir", Ci.nsILocalFile);
|
||||
this.appSupportDir.append("Application Support");
|
||||
|
||||
let filenameRE = new RegExp("[<>:\"/\\\\|\\?\\*]", "gi");
|
||||
this.appNameAsFilename = this.appNameAsFilename.replace(filenameRE, "");
|
||||
if (this.appNameAsFilename == "") {
|
||||
this.appNameAsFilename = "Webapp";
|
||||
}
|
||||
|
||||
// The ${ProfileDir} format is as follows:
|
||||
// host of the app origin + ";" +
|
||||
// protocol + ";" +
|
||||
// port (-1 for default port)
|
||||
this.appProfileDir = this.appSupportDir.clone();
|
||||
this.appProfileDir.append(this.launchURI.host + ";" +
|
||||
this.launchURI.scheme + ";" +
|
||||
this.launchURI.port);
|
||||
|
||||
this.installDir = Services.dirsvc.get("LocApp", Ci.nsILocalFile);
|
||||
this.installDir.append(this.appNameAsFilename + ".app");
|
||||
|
||||
this.contentsDir = this.installDir.clone();
|
||||
this.contentsDir.append("Contents");
|
||||
|
||||
this.macOSDir = this.contentsDir.clone();
|
||||
this.macOSDir.append("MacOS");
|
||||
|
||||
this.resourcesDir = this.contentsDir.clone();
|
||||
this.resourcesDir.append("Resources");
|
||||
|
||||
this.iconFile = this.resourcesDir.clone();
|
||||
this.iconFile.append("appicon.icns");
|
||||
|
||||
this.processFolder = Services.dirsvc.get("CurProcD", Ci.nsIFile);
|
||||
},
|
||||
|
||||
install: function() {
|
||||
this._removeInstallation(true);
|
||||
try {
|
||||
this._createDirectoryStructure();
|
||||
this._copyPrebuiltFiles();
|
||||
this._createConfigFiles();
|
||||
} catch (ex) {
|
||||
this._removeInstallation(false);
|
||||
throw(ex);
|
||||
}
|
||||
|
||||
getIconForApp(this);
|
||||
},
|
||||
|
||||
_removeInstallation: function(keepProfile) {
|
||||
try {
|
||||
if(this.installDir.exists()) {
|
||||
this.installDir.followLinks = false;
|
||||
this.installDir.remove(true);
|
||||
}
|
||||
} catch(ex) {
|
||||
}
|
||||
|
||||
if (keepProfile)
|
||||
return;
|
||||
|
||||
try {
|
||||
if(this.appProfileDir.exists()) {
|
||||
this.appProfileDir.followLinks = false;
|
||||
this.appProfileDir.remove(true);
|
||||
}
|
||||
} catch(ex) {
|
||||
}
|
||||
},
|
||||
|
||||
_createDirectoryStructure: function() {
|
||||
if (!this.appProfileDir.exists())
|
||||
this.appProfileDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
|
||||
|
||||
this.installDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
|
||||
this.contentsDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
|
||||
this.macOSDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
|
||||
this.resourcesDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
|
||||
},
|
||||
|
||||
_copyPrebuiltFiles: function() {
|
||||
let webapprt = this.processFolder.clone();
|
||||
webapprt.append("webapprt-stub");
|
||||
webapprt.copyTo(this.macOSDir, "webapprt");
|
||||
},
|
||||
|
||||
_createConfigFiles: function() {
|
||||
// ${ProfileDir}/config.json
|
||||
let json = {
|
||||
"app": {
|
||||
"profile": this.profileFolder.path,
|
||||
"origin": this.launchURI.prePath,
|
||||
"installOrigin": "apps.mozillalabs.com",
|
||||
"manifest": this.manifest
|
||||
}
|
||||
};
|
||||
|
||||
let configJson = this.appProfileDir.clone();
|
||||
configJson.append("webapp.json");
|
||||
writeToFile(configJson, JSON.stringify(json), function() {});
|
||||
|
||||
// ${InstallDir}/Contents/MacOS/webapp.ini
|
||||
let applicationINI = this.macOSDir.clone().QueryInterface(Ci.nsILocalFile);
|
||||
applicationINI.append("webapp.ini");
|
||||
|
||||
let factory = Cc["@mozilla.org/xpcom/ini-processor-factory;1"]
|
||||
.getService(Ci.nsIINIParserFactory);
|
||||
|
||||
let writer = factory.createINIParser(applicationINI).QueryInterface(Ci.nsIINIParserWriter);
|
||||
writer.setString("Webapp", "Name", this.appName);
|
||||
writer.setString("Webapp", "Profile", this.appProfileDir.leafName);
|
||||
writer.setString("Branding", "BrandFullName", this.appName);
|
||||
writer.setString("Branding", "BrandShortName", this.appName);
|
||||
writer.writeFile();
|
||||
|
||||
let infoPListContent = '<?xml version="1.0" encoding="UTF-8"?>\n\
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n\
|
||||
<plist version="1.0">\n\
|
||||
<dict>\n\
|
||||
<key>CFBundleDevelopmentRegion</key>\n\
|
||||
<string>English</string>\n\
|
||||
<key>CFBundleDisplayName</key>\n\
|
||||
<string>' + escapeXML(this.appName) + '</string>\n\
|
||||
<key>CFBundleExecutable</key>\n\
|
||||
<string>webapprt</string>\n\
|
||||
<key>CFBundleIconFile</key>\n\
|
||||
<string>appicon</string>\n\
|
||||
<key>CFBundleIdentifier</key>\n\
|
||||
<string>' + escapeXML(this.launchURI.prePath) + '</string>\n\
|
||||
<key>CFBundleInfoDictionaryVersion</key>\n\
|
||||
<string>6.0</string>\n\
|
||||
<key>CFBundleName</key>\n\
|
||||
<string>' + escapeXML(this.appName) + '</string>\n\
|
||||
<key>CFBundlePackageType</key>\n\
|
||||
<string>APPL</string>\n\
|
||||
<key>CFBundleSignature</key>\n\
|
||||
<string>MOZB</string>\n\
|
||||
<key>CFBundleVersion</key>\n\
|
||||
<string>0</string>\n\
|
||||
#ifdef DEBUG
|
||||
<key>FirefoxBinary</key>\n\
|
||||
<string>org.mozilla.NightlyDebug</string>\n\
|
||||
#endif
|
||||
</dict>\n\
|
||||
</plist>';
|
||||
|
||||
let infoPListFile = this.contentsDir.clone();
|
||||
infoPListFile.append("Info.plist");
|
||||
writeToFile(infoPListFile, infoPListContent, function() {});
|
||||
},
|
||||
|
||||
/**
|
||||
* This variable specifies if the icon retrieval process should
|
||||
* use a temporary file in the system or a binary stream. This
|
||||
* is accessed by a common function in WebappsIconHelpers.js and
|
||||
* is different for each platform.
|
||||
*/
|
||||
useTmpForIcon: true,
|
||||
|
||||
/**
|
||||
* Process the icon from the imageStream as retrieved from
|
||||
* the URL by getIconForApp(). This will bundle the icon to the
|
||||
* app package at Contents/Resources/appicon.icns.
|
||||
*
|
||||
* @param aMimeType the icon mimetype
|
||||
* @param aImageStream the stream for the image data
|
||||
* @param aCallback a callback function to be called
|
||||
* after the process finishes
|
||||
*/
|
||||
processIcon: function(aMimeType, aIcon) {
|
||||
try {
|
||||
let process = Cc["@mozilla.org/process/util;1"]
|
||||
.createInstance(Ci.nsIProcess);
|
||||
let sipsFile = Cc["@mozilla.org/file/local;1"]
|
||||
.createInstance(Ci.nsILocalFile);
|
||||
sipsFile.initWithPath("/usr/bin/sips");
|
||||
|
||||
process.init(sipsFile);
|
||||
process.run(true, ["-s",
|
||||
"format", "icns",
|
||||
aIcon.path,
|
||||
"--out", this.iconFile.path,
|
||||
"-z", "128", "128"],
|
||||
9);
|
||||
} catch(e) {
|
||||
throw(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Helper Functions */
|
||||
|
||||
/**
|
||||
* Async write a data string into a file
|
||||
*
|
||||
* @param aFile the nsIFile to write to
|
||||
* @param aData a string with the data to be written
|
||||
* @param aCallback a callback to be called after the process is finished
|
||||
*/
|
||||
function writeToFile(aFile, aData, aCallback) {
|
||||
let ostream = FileUtils.openSafeFileOutputStream(aFile);
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "UTF-8";
|
||||
let istream = converter.convertToInputStream(aData);
|
||||
NetUtil.asyncCopy(istream, ostream, function(x) aCallback(x));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes unprintable characters from a string.
|
||||
*/
|
||||
function sanitize(aStr) {
|
||||
let unprintableRE = new RegExp("[\\x00-\\x1F\\x7F]" ,"gi");
|
||||
return aStr.replace(unprintableRE, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips all non-word characters from the beginning and end of a string
|
||||
*/
|
||||
function stripStringForFilename(aPossiblyBadFilenameString) {
|
||||
//strip everything from the front up to the first [0-9a-zA-Z]
|
||||
|
||||
let stripFrontRE = new RegExp("^\\W*","gi");
|
||||
let stripBackRE = new RegExp("\\W*$","gi");
|
||||
|
||||
let stripped = aPossiblyBadFilenameString.replace(stripFrontRE, "");
|
||||
stripped = stripped.replace(stripBackRE, "");
|
||||
return stripped;
|
||||
}
|
||||
|
||||
function escapeXML(aStr) {
|
||||
return aStr.toString()
|
||||
.replace(/&/g, "&")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">");
|
||||
}
|
||||
|
||||
/* More helpers for handling the app icon */
|
||||
#include WebappsIconHelpers.js
|
|
@ -11,6 +11,7 @@ let Cu = Components.utils;
|
|||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Webapps.jsm");
|
||||
Cu.import("resource://gre/modules/WebappsInstaller.jsm");
|
||||
|
||||
let webappsUI = {
|
||||
init: function webappsUI_init() {
|
||||
|
@ -108,8 +109,11 @@ let webappsUI = {
|
|||
label: bundle.getString("webapps.install"),
|
||||
accessKey: bundle.getString("webapps.install.accesskey"),
|
||||
callback: function(notification) {
|
||||
installDone = true;
|
||||
DOMApplicationRegistry.confirmInstall(aData);
|
||||
if (WebappsInstaller.install(aData)) {
|
||||
DOMApplicationRegistry.confirmInstall(aData);
|
||||
} else {
|
||||
DOMApplicationRegistry.denyInstall(aData);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
После Ширина: | Высота: | Размер: 2.8 KiB |
После Ширина: | Высота: | Размер: 2.1 KiB |
После Ширина: | Высота: | Размер: 3.1 KiB |
|
@ -0,0 +1,279 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*** Panel and outer controls ***/
|
||||
|
||||
#downloadsPanel > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#downloadsListBox {
|
||||
width: 60ch;
|
||||
background: transparent;
|
||||
padding: 4px;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
#downloadsPanel:not([hasdownloads]) > #downloadsListBox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#downloadsHistory {
|
||||
background: inherit;
|
||||
color: -moz-nativehyperlinktext;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#downloadsPanel[hasdownloads] > #downloadsHistory {
|
||||
border-top: 1px solid ThreeDShadow;
|
||||
background-image: -moz-linear-gradient(hsla(0,0%,0%,.15), hsla(0,0%,0%,.08) 6px);
|
||||
}
|
||||
|
||||
#downloadsHistory > .button-box {
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
/*** List items ***/
|
||||
|
||||
richlistitem[type="download"] {
|
||||
height: 6em;
|
||||
margin: 0;
|
||||
border-top: 1px solid hsla(0,0%,100%,.2);
|
||||
border-bottom: 1px solid hsla(0,0%,0%,.15);
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
richlistitem[type="download"]:first-child {
|
||||
border-top: 1px solid transparent;
|
||||
}
|
||||
|
||||
richlistitem[type="download"]:last-child {
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
|
||||
#downloadsListBox:-moz-focusring > richlistitem[type="download"][selected] {
|
||||
outline: 1px #999 dotted;
|
||||
outline-offset: -1px;
|
||||
-moz-outline-radius: 3px;
|
||||
}
|
||||
|
||||
.downloadInfo {
|
||||
padding: 8px;
|
||||
-moz-padding-end: 0;
|
||||
}
|
||||
|
||||
.downloadTypeIcon {
|
||||
-moz-margin-end: 8px;
|
||||
/* Prevent flickering when changing states. */
|
||||
min-height: 32px;
|
||||
min-width: 32px;
|
||||
}
|
||||
|
||||
.blockedIcon {
|
||||
list-style-image: url("chrome://global/skin/icons/Error.png");
|
||||
}
|
||||
|
||||
.downloadTarget {
|
||||
margin-bottom: 7px;
|
||||
cursor: inherit;
|
||||
}
|
||||
|
||||
.downloadDetails {
|
||||
margin-top: 1px;
|
||||
opacity: 0.6;
|
||||
font-size: 90%;
|
||||
cursor: inherit;
|
||||
}
|
||||
|
||||
.downloadButton {
|
||||
-moz-appearance: none;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
margin: 6px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
padding: 5px;
|
||||
list-style-image: url("chrome://browser/skin/downloads/buttons.png");
|
||||
}
|
||||
|
||||
.downloadButton > .button-box {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*** Highlighted list items ***/
|
||||
|
||||
richlistitem[type="download"][state="1"] > .downloadInfo {
|
||||
border-top: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
-moz-padding-end: 8px;
|
||||
}
|
||||
|
||||
richlistitem[type="download"][state="1"] > .downloadInfo:hover {
|
||||
border-radius: 3px;
|
||||
border-top: 1px solid hsla(0,0%,100%,.3);
|
||||
border-bottom: 1px solid hsla(0,0%,0%,.2);
|
||||
background-color: Highlight;
|
||||
background-image: -moz-linear-gradient(hsla(0,0%,100%,.1), hsla(0,0%,100%,0));
|
||||
color: HighlightText;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*** Button icons ***/
|
||||
|
||||
.downloadButton.downloadCancel {
|
||||
-moz-image-region: rect(0px, 14px, 14px, 0px);
|
||||
}
|
||||
.downloadButton.downloadCancel:hover {
|
||||
-moz-image-region: rect(0px, 28px, 14px, 14px);
|
||||
}
|
||||
.downloadButton.downloadCancel:active {
|
||||
-moz-image-region: rect(0px, 42px, 14px, 28px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadShow {
|
||||
-moz-image-region: rect(14px, 14px, 28px, 0px);
|
||||
}
|
||||
.downloadButton.downloadShow:hover {
|
||||
-moz-image-region: rect(14px, 28px, 28px, 14px);
|
||||
}
|
||||
.downloadButton.downloadShow:active {
|
||||
-moz-image-region: rect(14px, 42px, 28px, 28px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadRetry {
|
||||
-moz-image-region: rect(28px, 14px, 42px, 0px);
|
||||
}
|
||||
.downloadButton.downloadRetry:hover {
|
||||
-moz-image-region: rect(28px, 28px, 42px, 14px);
|
||||
}
|
||||
.downloadButton.downloadRetry:active {
|
||||
-moz-image-region: rect(28px, 42px, 42px, 28px);
|
||||
}
|
||||
|
||||
/*** Status and progress indicator ***/
|
||||
|
||||
#downloads-indicator {
|
||||
width: 35px;
|
||||
}
|
||||
|
||||
#downloads-indicator-anchor {
|
||||
min-width: 18px;
|
||||
min-height: 18px;
|
||||
/* Makes the outermost stack element positioned, so that its contents are
|
||||
rendered over the main browser window in the Z order. This is required by
|
||||
the animated event notification. */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/*** Main indicator icon ***/
|
||||
|
||||
#downloads-indicator-icon {
|
||||
background: -moz-image-rect(url("chrome://browser/skin/Toolbar-small.png"),
|
||||
0, 16, 16, 0) center no-repeat;
|
||||
}
|
||||
|
||||
#downloads-indicator-icon:-moz-lwtheme-brighttext {
|
||||
background: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"),
|
||||
0, 16, 16, 0) center no-repeat;
|
||||
}
|
||||
|
||||
#downloads-indicator[attention] > #downloads-indicator-anchor > #downloads-indicator-icon {
|
||||
background: -moz-image-rect(url("chrome://browser/skin/downloads/download-glow.png"),
|
||||
16, 32, 32, 16) center no-repeat;
|
||||
}
|
||||
|
||||
#downloads-indicator:not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
|
||||
background: -moz-image-rect(url("chrome://browser/skin/Toolbar-small.png"),
|
||||
0, 16, 16, 0) center no-repeat;
|
||||
background-size: 12px;
|
||||
}
|
||||
|
||||
#downloads-indicator:not([counter])[attention] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
|
||||
background-image: -moz-image-rect(url("chrome://browser/skin/downloads/download-glow.png"),
|
||||
16, 32, 32, 16);
|
||||
}
|
||||
|
||||
/*** Event notification ***/
|
||||
|
||||
#downloads-indicator-notification {
|
||||
opacity: 0;
|
||||
background: url("chrome://browser/skin/downloads/download-notification.png")
|
||||
center no-repeat;
|
||||
background-size: 16px;
|
||||
}
|
||||
|
||||
@-moz-keyframes downloadsIndicatorNotificationRight {
|
||||
from { opacity: 0; -moz-transform: translate(-128px, 128px) scale(8); }
|
||||
20% { opacity: .85; -moz-animation-timing-function: ease-out; }
|
||||
to { opacity: 0; -moz-transform: translate(0) scale(1); }
|
||||
}
|
||||
|
||||
@-moz-keyframes downloadsIndicatorNotificationLeft {
|
||||
from { opacity: 0; -moz-transform: translate(128px, 128px) scale(8); }
|
||||
20% { opacity: .85; -moz-animation-timing-function: ease-out; }
|
||||
to { opacity: 0; -moz-transform: translate(0) scale(1); }
|
||||
}
|
||||
|
||||
#downloads-indicator[notification] > #downloads-indicator-anchor > #downloads-indicator-notification {
|
||||
-moz-animation-name: downloadsIndicatorNotificationRight;
|
||||
-moz-animation-duration: 1s;
|
||||
}
|
||||
|
||||
#downloads-indicator[notification]:-moz-locale-dir(rtl) > #downloads-indicator-anchor > #downloads-indicator-notification {
|
||||
-moz-animation-name: downloadsIndicatorNotificationLeft;
|
||||
}
|
||||
|
||||
/*** Progress bar and text ***/
|
||||
|
||||
#downloads-indicator-counter {
|
||||
height: 12px;
|
||||
margin: 0;
|
||||
color: hsl(0,0%,30%);
|
||||
text-shadow: 0 1px 0 hsla(0,0%,100%,.5);
|
||||
font-size: 10px;
|
||||
line-height: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#downloads-indicator-progress {
|
||||
width: 24px;
|
||||
height: 4px;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
margin-top: 1px;
|
||||
margin-bottom: 2px;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.4);
|
||||
}
|
||||
|
||||
#downloads-indicator-progress > .progress-bar {
|
||||
-moz-appearance: none;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
background-image: -moz-linear-gradient(#41a0ff, #2090ff);
|
||||
border: 1px solid;
|
||||
border-color: hsla(0,0%,0%,.6) hsla(0,0%,0%,.2) hsla(0,0%,0%,.2);
|
||||
border-radius: 2px 0 0 2px;
|
||||
}
|
||||
|
||||
#downloads-indicator-progress > .progress-remainder {
|
||||
-moz-appearance: none;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
background-image: -moz-linear-gradient(#9a9a9a, #a1a1a1);
|
||||
border: 1px solid;
|
||||
border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.3) hsla(0,0%,0%,.2);
|
||||
-moz-border-start: none;
|
||||
border-radius: 0 2px 2px 0;
|
||||
}
|
||||
|
||||
#downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-bar {
|
||||
background-image: -moz-linear-gradient(#a0a000, #909000);
|
||||
}
|
||||
|
||||
#downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder {
|
||||
background-image: -moz-linear-gradient(#9a9a00, #a1a100);
|
||||
}
|
|
@ -35,6 +35,10 @@ browser.jar:
|
|||
skin/classic/browser/Toolbar.png
|
||||
skin/classic/browser/Toolbar-small.png
|
||||
skin/classic/browser/urlbar-arrow.png
|
||||
skin/classic/browser/downloads/buttons.png (downloads/buttons.png)
|
||||
skin/classic/browser/downloads/download-glow.png (downloads/download-glow.png)
|
||||
skin/classic/browser/downloads/download-notification.png (downloads/download-notification.png)
|
||||
skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
|
||||
skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png)
|
||||
skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png)
|
||||
skin/classic/browser/feeds/videoFeedIcon.png (feeds/feedIcon.png)
|
||||
|
|
После Ширина: | Высота: | Размер: 1.6 KiB |
После Ширина: | Высота: | Размер: 2.2 KiB |
После Ширина: | Высота: | Размер: 3.1 KiB |
|
@ -0,0 +1,300 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*** Panel and outer controls ***/
|
||||
|
||||
#downloadsPanel > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#downloadsListBox {
|
||||
width: 60ch;
|
||||
background: transparent;
|
||||
padding: 4px;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
#downloadsPanel:not([hasdownloads]) > #downloadsListBox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#downloadsHistory {
|
||||
background: inherit;
|
||||
border-bottom-left-radius: 6px;
|
||||
border-bottom-right-radius: 6px;
|
||||
color: hsl(210,100%,75%);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#downloadsPanel:not([hasdownloads]) > #downloadsHistory {
|
||||
border-top-left-radius: 6px;
|
||||
border-top-right-radius: 6px;
|
||||
}
|
||||
|
||||
#downloadsPanel[hasdownloads] > #downloadsHistory {
|
||||
border-top: 1px solid hsla(0,0%,100%,.1);
|
||||
background-color: hsla(0,0%,7%,.3);
|
||||
box-shadow: 0 1px 1px hsla(0,0%,0%,.25) inset;
|
||||
}
|
||||
|
||||
#downloadsHistory > .button-box {
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
#downloadsHistory:-moz-focusring > .button-box {
|
||||
border-top-left-radius: 6px;
|
||||
border-top-right-radius: 6px;
|
||||
}
|
||||
|
||||
#downloadsPanel:not([hasdownloads]) > #downloadsHistory:-moz-focusring > .button-box {
|
||||
border-bottom-left-radius: 6px;
|
||||
border-bottom-right-radius: 6px;
|
||||
}
|
||||
|
||||
/*** List items ***/
|
||||
|
||||
richlistitem[type="download"] {
|
||||
height: 7em;
|
||||
margin: 0;
|
||||
border-top: 1px solid hsla(0,0%,100%,.07);
|
||||
border-bottom: 1px solid hsla(0,0%,0%,.2);
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
richlistitem[type="download"]:first-child {
|
||||
border-top: 1px solid transparent;
|
||||
}
|
||||
|
||||
richlistitem[type="download"]:last-child {
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
|
||||
#downloadsListBox:-moz-focusring > richlistitem[type="download"][selected] {
|
||||
outline: 1px #999 dotted;
|
||||
outline-offset: -1px;
|
||||
-moz-outline-radius: 3px;
|
||||
}
|
||||
|
||||
.downloadInfo {
|
||||
color: white;
|
||||
padding: 8px;
|
||||
-moz-padding-end: 0;
|
||||
}
|
||||
|
||||
.downloadTypeIcon {
|
||||
-moz-margin-end: 8px;
|
||||
/* Prevent flickering when changing states. */
|
||||
min-height: 32px;
|
||||
min-width: 32px;
|
||||
}
|
||||
|
||||
.blockedIcon {
|
||||
list-style-image: url("chrome://global/skin/icons/Error.png");
|
||||
}
|
||||
|
||||
.downloadTarget {
|
||||
margin-bottom: 6px;
|
||||
cursor: inherit;
|
||||
}
|
||||
|
||||
.downloadDetails {
|
||||
opacity: 0.7;
|
||||
font-size: 95%;
|
||||
cursor: inherit;
|
||||
}
|
||||
|
||||
.downloadButton {
|
||||
-moz-appearance: none;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
margin: 6px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
padding: 5px;
|
||||
list-style-image: url("chrome://browser/skin/downloads/buttons.png");
|
||||
}
|
||||
|
||||
.downloadButton > .button-box {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*** Highlighted list items ***/
|
||||
|
||||
richlistitem[type="download"][state="1"] .downloadInfo {
|
||||
border-top: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
-moz-padding-end: 8px;
|
||||
}
|
||||
|
||||
richlistitem[type="download"][state="1"] .downloadInfo:hover {
|
||||
border-radius: 3px;
|
||||
border-top: 1px solid hsla(0,0%,100%,.2);
|
||||
border-bottom: 1px solid hsla(0,0%,0%,.4);
|
||||
background-color: Highlight;
|
||||
background-image: -moz-linear-gradient(hsl(210,100%,50%), hsl(210,96%,41%));
|
||||
color: HighlightText;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*** Button icons ***/
|
||||
|
||||
.downloadButton.downloadCancel {
|
||||
-moz-image-region: rect(0px, 14px, 14px, 0px);
|
||||
}
|
||||
.downloadButton.downloadCancel:hover {
|
||||
-moz-image-region: rect(0px, 28px, 14px, 14px);
|
||||
}
|
||||
.downloadButton.downloadCancel:active {
|
||||
-moz-image-region: rect(0px, 42px, 14px, 28px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadShow {
|
||||
-moz-image-region: rect(14px, 14px, 28px, 0px);
|
||||
}
|
||||
.downloadButton.downloadShow:hover {
|
||||
-moz-image-region: rect(14px, 28px, 28px, 14px);
|
||||
}
|
||||
.downloadButton.downloadShow:active {
|
||||
-moz-image-region: rect(14px, 42px, 28px, 28px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadRetry {
|
||||
-moz-image-region: rect(28px, 14px, 42px, 0px);
|
||||
}
|
||||
.downloadButton.downloadRetry:hover {
|
||||
-moz-image-region: rect(28px, 28px, 42px, 14px);
|
||||
}
|
||||
.downloadButton.downloadRetry:active {
|
||||
-moz-image-region: rect(28px, 42px, 42px, 28px);
|
||||
}
|
||||
|
||||
/*** Status and progress indicator ***/
|
||||
|
||||
#downloads-indicator {
|
||||
width: 35px;
|
||||
}
|
||||
|
||||
#downloads-indicator-anchor {
|
||||
min-width: 20px;
|
||||
min-height: 20px;
|
||||
/* Makes the outermost stack element positioned, so that its contents are
|
||||
rendered over the main browser window in the Z order. This is required by
|
||||
the animated event notification. */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/*** Main indicator icon ***/
|
||||
|
||||
#downloads-indicator-icon {
|
||||
background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
|
||||
0, 140, 20, 120) center no-repeat;
|
||||
}
|
||||
|
||||
#downloads-indicator-icon:-moz-lwtheme-brighttext {
|
||||
background: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"),
|
||||
0, 140, 20, 120) center no-repeat;
|
||||
}
|
||||
|
||||
#downloads-indicator[attention]
|
||||
#downloads-indicator-icon {
|
||||
background: -moz-image-rect(url("chrome://browser/skin/downloads/download-glow.png"),
|
||||
14, 34, 34, 14) center no-repeat;
|
||||
}
|
||||
|
||||
#downloads-indicator:not([counter])
|
||||
#downloads-indicator-counter {
|
||||
background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
|
||||
0, 140, 20, 120) center no-repeat;
|
||||
background-size: 12px;
|
||||
}
|
||||
|
||||
#downloads-indicator:not([counter])[attention]
|
||||
#downloads-indicator-counter {
|
||||
background-image: -moz-image-rect(url("chrome://browser/skin/downloads/download-glow.png"),
|
||||
14, 34, 34, 14);
|
||||
}
|
||||
|
||||
/*** Event notification ***/
|
||||
|
||||
#downloads-indicator-notification {
|
||||
opacity: 0;
|
||||
background: url("chrome://browser/skin/downloads/download-notification.png")
|
||||
center no-repeat;
|
||||
background-size: 16px;
|
||||
}
|
||||
|
||||
@-moz-keyframes downloadsIndicatorNotificationRight {
|
||||
from { opacity: 0; -moz-transform: translate(-128px, 128px) scale(8); }
|
||||
20% { opacity: .85; -moz-animation-timing-function: ease-out; }
|
||||
to { opacity: 0; -moz-transform: translate(0) scale(1); }
|
||||
}
|
||||
|
||||
@-moz-keyframes downloadsIndicatorNotificationLeft {
|
||||
from { opacity: 0; -moz-transform: translate(128px, 128px) scale(8); }
|
||||
20% { opacity: .85; -moz-animation-timing-function: ease-out; }
|
||||
to { opacity: 0; -moz-transform: translate(0) scale(1); }
|
||||
}
|
||||
|
||||
#downloads-indicator[notification] > #downloads-indicator-anchor > #downloads-indicator-notification {
|
||||
-moz-animation-name: downloadsIndicatorNotificationRight;
|
||||
-moz-animation-duration: 1s;
|
||||
}
|
||||
|
||||
#downloads-indicator[notification]:-moz-locale-dir(rtl) > #downloads-indicator-anchor > #downloads-indicator-notification {
|
||||
-moz-animation-name: downloadsIndicatorNotificationLeft;
|
||||
}
|
||||
|
||||
/*** Progress bar and text ***/
|
||||
|
||||
#downloads-indicator-counter {
|
||||
height: 12px;
|
||||
margin: 0;
|
||||
color: hsl(0,0%,30%);
|
||||
text-shadow: 0 1px 0 hsla(0,0%,100%,.5);
|
||||
font-size: 10px;
|
||||
line-height: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#downloads-indicator-progress {
|
||||
width: 24px;
|
||||
height: 4px;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
margin-top: 1px;
|
||||
margin-bottom: 2px;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.4);
|
||||
}
|
||||
|
||||
#downloads-indicator-progress > .progress-bar {
|
||||
-moz-appearance: none;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
background-image: -moz-linear-gradient(#41a0ff, #2090ff);
|
||||
border: 1px solid;
|
||||
border-color: hsla(0,0%,0%,.6) hsla(0,0%,0%,.2) hsla(0,0%,0%,.2);
|
||||
border-radius: 2px 0 0 2px;
|
||||
}
|
||||
|
||||
#downloads-indicator-progress > .progress-remainder {
|
||||
-moz-appearance: none;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
background-image: -moz-linear-gradient(#9a9a9a, #a1a1a1);
|
||||
border: 1px solid;
|
||||
border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.3) hsla(0,0%,0%,.2);
|
||||
-moz-border-start: none;
|
||||
border-radius: 0 2px 2px 0;
|
||||
}
|
||||
|
||||
#downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-bar {
|
||||
background-image: -moz-linear-gradient(#a0a000, #909000);
|
||||
}
|
||||
|
||||
#downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder {
|
||||
background-image: -moz-linear-gradient(#9a9a00, #a1a100);
|
||||
}
|
|
@ -45,6 +45,10 @@ browser.jar:
|
|||
skin/classic/browser/urlbar-history-dropmarker.png
|
||||
skin/classic/browser/urlbar-arrow.png
|
||||
skin/classic/browser/urlbar-popup-blocked.png
|
||||
skin/classic/browser/downloads/buttons.png (downloads/buttons.png)
|
||||
skin/classic/browser/downloads/download-glow.png (downloads/download-glow.png)
|
||||
skin/classic/browser/downloads/download-notification.png (downloads/download-notification.png)
|
||||
skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
|
||||
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
|
||||
skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
|
||||
skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png)
|
||||
|
|
После Ширина: | Высота: | Размер: 3.1 KiB |
После Ширина: | Высота: | Размер: 3.1 KiB |
После Ширина: | Высота: | Размер: 2.5 KiB |
После Ширина: | Высота: | Размер: 2.1 KiB |
После Ширина: | Высота: | Размер: 3.1 KiB |
|
@ -0,0 +1,49 @@
|
|||
%define WINSTRIPE_AERO
|
||||
%include downloads.css
|
||||
%undef WINSTRIPE_AERO
|
||||
|
||||
#downloadsPanel > .panel-arrowcontainer > .panel-arrowcontent > .panel-inner-arrowcontent {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media (-moz-windows-default-theme) {
|
||||
#downloadsPanel[hasdownloads] > #downloadsHistory {
|
||||
background-color: #f1f5fb;
|
||||
}
|
||||
|
||||
richlistitem[type="download"] {
|
||||
border: 1px solid transparent;
|
||||
border-bottom: 1px solid hsl(213,40%,90%);
|
||||
}
|
||||
|
||||
richlistitem[type="download"][state="1"] > .downloadInfo {
|
||||
border: 1px solid transparent;
|
||||
-moz-padding-end: 8px;
|
||||
}
|
||||
|
||||
richlistitem[type="download"][state="1"] > .downloadInfo:hover {
|
||||
border: 1px solid hsl(213,45%,65%);
|
||||
box-shadow: 0 0 0 1px hsla(0,0%,100%,.5) inset,
|
||||
0 1px 0 hsla(0,0%,100%,.3) inset;
|
||||
background-image: -moz-linear-gradient(hsl(212,86%,92%), hsl(212,91%,86%));
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
|
||||
@media (-moz-windows-compositor) {
|
||||
#toolbar-menubar #downloads-indicator-icon:not(:-moz-lwtheme),
|
||||
#TabsToolbar[tabsontop=true] #downloads-indicator-icon:not(:-moz-lwtheme),
|
||||
#navigator-toolbox[tabsontop=false] > #nav-bar #downloads-indicator-icon:not(:-moz-lwtheme),
|
||||
#nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child #downloads-indicator-icon:not(:-moz-lwtheme) {
|
||||
list-style-image: url("chrome://browser/skin/Toolbar-inverted.png");
|
||||
}
|
||||
|
||||
#toolbar-menubar #downloads-indicator-counter:not(:-moz-lwtheme),
|
||||
#TabsToolbar[tabsontop=true] #downloads-indicator-counter:not(:-moz-lwtheme),
|
||||
#navigator-toolbox[tabsontop=false] > #nav-bar #downloads-indicator-counter:not(:-moz-lwtheme),
|
||||
#nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child #downloads-indicator-counter:not(:-moz-lwtheme) {
|
||||
color: white;
|
||||
text-shadow: 0 0 1px rgba(0,0,0,.7),
|
||||
0 1px 1.5px rgba(0,0,0,.5);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,310 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*** Panel and outer controls ***/
|
||||
|
||||
%ifndef WINSTRIPE_AERO
|
||||
#downloadsHistory,
|
||||
#downloadsHistory:-moz-focusring > .button-box {
|
||||
border-bottom-left-radius: 6px;
|
||||
border-bottom-right-radius: 6px;
|
||||
}
|
||||
|
||||
#downloadsPanel:not([hasdownloads]) > #downloadsHistory,
|
||||
#downloadsPanel:not([hasdownloads]) > #downloadsHistory:-moz-focusring > .button-box {
|
||||
border-top-left-radius: 6px;
|
||||
border-top-right-radius: 6px;
|
||||
}
|
||||
|
||||
#downloadsPanel > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
/* Avoid that the arrow overlaps the selection on first item */
|
||||
padding-top: 5px;
|
||||
}
|
||||
%endif
|
||||
|
||||
#downloadsPanel > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#downloadsListBox {
|
||||
width: 60ch;
|
||||
background-color: transparent;
|
||||
padding: 4px;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
#downloadsHistory {
|
||||
background: inherit;
|
||||
color: -moz-nativehyperlinktext;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#downloadsHistory > .button-box {
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
@media (-moz-windows-default-theme) {
|
||||
#downloadsPanel[hasdownloads] > #downloadsHistory {
|
||||
background-color: hsla(216,45%,88%,.98);
|
||||
box-shadow: 0px 1px 2px rgb(204,214,234) inset;
|
||||
}
|
||||
}
|
||||
|
||||
/*** List items ***/
|
||||
|
||||
richlistitem[type="download"] {
|
||||
height: 7em;
|
||||
margin: 0;
|
||||
border-top: 1px solid hsla(0,0%,100%,.3);
|
||||
border-bottom: 1px solid hsla(220,18%,51%,.25);
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
richlistitem[type="download"]:first-child {
|
||||
border-top: 1px solid transparent;
|
||||
}
|
||||
|
||||
@media (-moz-windows-default-theme) {
|
||||
richlistitem[type="download"]:last-child {
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
}
|
||||
|
||||
#downloadsListBox:-moz-focusring > richlistitem[type="download"][selected] {
|
||||
outline: 1px #999 dotted;
|
||||
outline-offset: -1px;
|
||||
-moz-outline-radius: 3px;
|
||||
}
|
||||
|
||||
.downloadInfo {
|
||||
padding: 8px;
|
||||
-moz-padding-end: 0;
|
||||
}
|
||||
|
||||
.downloadTypeIcon {
|
||||
-moz-margin-end: 8px;
|
||||
/* Prevent flickering when changing states. */
|
||||
min-height: 32px;
|
||||
min-width: 32px;
|
||||
}
|
||||
|
||||
.blockedIcon {
|
||||
list-style-image: url("chrome://global/skin/icons/Error.png");
|
||||
}
|
||||
|
||||
.downloadTarget {
|
||||
margin-bottom: 6px;
|
||||
cursor: inherit;
|
||||
}
|
||||
|
||||
.downloadDetails {
|
||||
opacity: 0.6;
|
||||
font-size: 90%;
|
||||
cursor: inherit;
|
||||
}
|
||||
|
||||
.downloadButton {
|
||||
-moz-appearance: none;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
margin: 6px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
padding: 5px;
|
||||
list-style-image: url("chrome://browser/skin/downloads/buttons.png");
|
||||
}
|
||||
|
||||
.downloadButton > .button-box {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*** Highlighted list items ***/
|
||||
|
||||
%ifdef WINSTRIPE_AERO
|
||||
@media not all and (-moz-windows-default-theme) {
|
||||
%endif
|
||||
|
||||
richlistitem[type="download"][state="1"] > .downloadInfo {
|
||||
border-top: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
-moz-padding-end: 8px;
|
||||
}
|
||||
|
||||
%ifdef WINSTRIPE_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
richlistitem[type="download"][state="1"] > .downloadInfo:hover {
|
||||
border-radius: 3px;
|
||||
border-top: 1px solid hsla(0,0%,100%,.2);
|
||||
border-bottom: 1px solid hsla(0,0%,0%,.2);
|
||||
background-color: Highlight;
|
||||
color: HighlightText;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*** Button icons ***/
|
||||
|
||||
.downloadButton.downloadCancel {
|
||||
-moz-image-region: rect(0px, 14px, 14px, 0px);
|
||||
}
|
||||
.downloadButton.downloadCancel:hover {
|
||||
-moz-image-region: rect(0px, 28px, 14px, 14px);
|
||||
}
|
||||
.downloadButton.downloadCancel:active {
|
||||
-moz-image-region: rect(0px, 42px, 14px, 28px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadShow {
|
||||
-moz-image-region: rect(14px, 14px, 28px, 0px);
|
||||
}
|
||||
.downloadButton.downloadShow:hover {
|
||||
-moz-image-region: rect(14px, 28px, 28px, 14px);
|
||||
}
|
||||
.downloadButton.downloadShow:active {
|
||||
-moz-image-region: rect(14px, 42px, 28px, 28px);
|
||||
}
|
||||
|
||||
.downloadButton.downloadRetry {
|
||||
-moz-image-region: rect(28px, 14px, 42px, 0px);
|
||||
}
|
||||
.downloadButton.downloadRetry:hover {
|
||||
-moz-image-region: rect(28px, 28px, 42px, 14px);
|
||||
}
|
||||
.downloadButton.downloadRetry:active {
|
||||
-moz-image-region: rect(28px, 42px, 42px, 28px);
|
||||
}
|
||||
|
||||
/*** Status and progress indicator ***/
|
||||
|
||||
#downloads-indicator {
|
||||
width: 35px;
|
||||
}
|
||||
|
||||
#downloads-indicator-anchor {
|
||||
min-width: 18px;
|
||||
min-height: 18px;
|
||||
/* Makes the outermost stack element positioned, so that its contents are
|
||||
rendered over the main browser window in the Z order. This is required by
|
||||
the animated event notification. */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/*** Main indicator icon ***/
|
||||
|
||||
#downloads-indicator-icon {
|
||||
background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
|
||||
0, 108, 18, 90) center no-repeat;
|
||||
}
|
||||
|
||||
#downloads-indicator-icon:-moz-lwtheme-brighttext {
|
||||
background: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"),
|
||||
0, 108, 18, 90) center no-repeat;
|
||||
}
|
||||
|
||||
#downloads-indicator[attention] > #downloads-indicator-anchor > #downloads-indicator-icon {
|
||||
background: -moz-image-rect(url("chrome://browser/skin/downloads/download-glow.png"),
|
||||
15, 33, 33, 15) center no-repeat;
|
||||
}
|
||||
|
||||
#downloads-indicator:not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
|
||||
background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
|
||||
0, 108, 18, 90) center no-repeat;
|
||||
background-size: 12px;
|
||||
}
|
||||
|
||||
#downloads-indicator:not([counter])[attention] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
|
||||
background-image: -moz-image-rect(url("chrome://browser/skin/downloads/download-glow.png"),
|
||||
16, 32, 32, 16);
|
||||
}
|
||||
|
||||
/*** Event notification ***/
|
||||
|
||||
#downloads-indicator-notification {
|
||||
opacity: 0;
|
||||
background: url("chrome://browser/skin/downloads/download-notification.png")
|
||||
center no-repeat;
|
||||
background-size: 16px;
|
||||
}
|
||||
|
||||
@-moz-keyframes downloadsIndicatorNotificationRight {
|
||||
from { opacity: 0; -moz-transform: translate(-128px, 128px) scale(8); }
|
||||
20% { opacity: .85; -moz-animation-timing-function: ease-out; }
|
||||
to { opacity: 0; -moz-transform: translate(0) scale(1); }
|
||||
}
|
||||
|
||||
@-moz-keyframes downloadsIndicatorNotificationLeft {
|
||||
from { opacity: 0; -moz-transform: translate(128px, 128px) scale(8); }
|
||||
20% { opacity: .85; -moz-animation-timing-function: ease-out; }
|
||||
to { opacity: 0; -moz-transform: translate(0) scale(1); }
|
||||
}
|
||||
|
||||
#downloads-indicator[notification] > #downloads-indicator-anchor > #downloads-indicator-notification {
|
||||
-moz-animation-name: downloadsIndicatorNotificationRight;
|
||||
-moz-animation-duration: 1s;
|
||||
}
|
||||
|
||||
#downloads-indicator[notification]:-moz-locale-dir(rtl) > #downloads-indicator-anchor > #downloads-indicator-notification {
|
||||
-moz-animation-name: downloadsIndicatorNotificationLeft;
|
||||
}
|
||||
|
||||
/*** Progress bar and text ***/
|
||||
|
||||
#downloads-indicator-counter {
|
||||
height: 12px;
|
||||
margin: 0;
|
||||
color: hsl(0,0%,30%);
|
||||
text-shadow: hsla(0,0%,100%,.5) 0 1px;
|
||||
font-size: 10px;
|
||||
line-height: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#downloads-indicator-counter:-moz-lwtheme-brighttext {
|
||||
color: white;
|
||||
text-shadow: 0 0 1px rgba(0,0,0,.7),
|
||||
0 1px 1.5px rgba(0,0,0,.5);
|
||||
}
|
||||
|
||||
#downloads-indicator-progress {
|
||||
width: 24px;
|
||||
height: 4px;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
margin-top: 1px;
|
||||
margin-bottom: 2px;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.4);
|
||||
}
|
||||
|
||||
#downloads-indicator-progress > .progress-bar {
|
||||
-moz-appearance: none;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
background-image: -moz-linear-gradient(#92DDA0, #6FC483 49%, #5EB272 51%, #80CE91);
|
||||
border: 1px solid;
|
||||
border-color: hsla(0,0%,0%,.6) hsla(0,0%,0%,.2) hsla(0,0%,0%,.2);
|
||||
border-radius: 2px 0 0 2px;
|
||||
}
|
||||
|
||||
#downloads-indicator-progress > .progress-remainder {
|
||||
-moz-appearance: none;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
background-image: -moz-linear-gradient(#9a9a9a, #a1a1a1);
|
||||
border: 1px solid;
|
||||
border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.3) hsla(0,0%,0%,.2);
|
||||
-moz-border-start: none;
|
||||
border-radius: 0 2px 2px 0;
|
||||
}
|
||||
|
||||
#downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-bar {
|
||||
background-image: -moz-linear-gradient(#DDDD00, #C4C400 49%, #B2B200 51%, #CECE00);
|
||||
}
|
||||
|
||||
#downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder {
|
||||
background-image: -moz-linear-gradient(#9a9a00, #a1a100);
|
||||
}
|
|
@ -50,6 +50,10 @@ browser.jar:
|
|||
skin/classic/browser/urlbar-arrow.png
|
||||
skin/classic/browser/urlbar-popup-blocked.png
|
||||
skin/classic/browser/urlbar-history-dropmarker.png
|
||||
skin/classic/browser/downloads/buttons.png (downloads/buttons.png)
|
||||
skin/classic/browser/downloads/download-glow.png (downloads/download-glow.png)
|
||||
skin/classic/browser/downloads/download-notification.png (downloads/download-notification.png)
|
||||
* skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
|
||||
skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png)
|
||||
skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png)
|
||||
skin/classic/browser/feeds/audioFeedIcon.png (feeds/feedIcon.png)
|
||||
|
@ -224,6 +228,10 @@ browser.jar:
|
|||
skin/classic/aero/browser/urlbar-arrow.png
|
||||
skin/classic/aero/browser/urlbar-popup-blocked.png
|
||||
skin/classic/aero/browser/urlbar-history-dropmarker.png
|
||||
skin/classic/aero/browser/downloads/buttons.png (downloads/buttons-aero.png)
|
||||
skin/classic/aero/browser/downloads/download-glow.png (downloads/download-glow-aero.png)
|
||||
skin/classic/aero/browser/downloads/download-notification.png (downloads/download-notification.png)
|
||||
* skin/classic/aero/browser/downloads/downloads.css (downloads/downloads-aero.css)
|
||||
skin/classic/aero/browser/feeds/feedIcon.png (feeds/feedIcon-aero.png)
|
||||
skin/classic/aero/browser/feeds/feedIcon16.png (feeds/feedIcon16-aero.png)
|
||||
skin/classic/aero/browser/feeds/audioFeedIcon.png (feeds/feedIcon-aero.png)
|
||||
|
|
|
@ -680,6 +680,8 @@ MOZ_THEME_FASTSTRIPE = @MOZ_THEME_FASTSTRIPE@
|
|||
|
||||
MOZ_SERVICES_SYNC = @MOZ_SERVICES_SYNC@
|
||||
|
||||
MOZ_WEBAPP_RUNTIME = @MOZ_WEBAPP_RUNTIME@
|
||||
|
||||
MOZ_OFFICIAL_BRANDING = @MOZ_OFFICIAL_BRANDING@
|
||||
|
||||
HAVE_CLOCK_MONOTONIC = @HAVE_CLOCK_MONOTONIC@
|
||||
|
|
41
configure.in
|
@ -4497,6 +4497,7 @@ MOZ_BRANDING_DIRECTORY=
|
|||
MOZ_OFFICIAL_BRANDING=
|
||||
MOZ_FEEDS=1
|
||||
MOZ_FLEXBOX=
|
||||
MOZ_WEBAPP_RUNTIME=
|
||||
MOZ_JSDEBUGGER=1
|
||||
MOZ_AUTH_EXTENSION=1
|
||||
MOZ_OGG=1
|
||||
|
@ -4559,6 +4560,7 @@ MOZ_GRAPHITE=1
|
|||
case "${target}" in
|
||||
*darwin*)
|
||||
ACCESSIBILITY=
|
||||
MOZ_WEBAPP_RUNTIME=1
|
||||
;;
|
||||
*)
|
||||
ACCESSIBILITY=1
|
||||
|
@ -4569,6 +4571,7 @@ case "$target_os" in
|
|||
mingw*)
|
||||
NS_ENABLE_TSF=1
|
||||
AC_DEFINE(NS_ENABLE_TSF)
|
||||
MOZ_WEBAPP_RUNTIME=1
|
||||
;;
|
||||
esac
|
||||
|
||||
|
@ -6274,6 +6277,44 @@ if test -n "$MOZ_TREE_FREETYPE"; then
|
|||
AC_SUBST(CAIRO_FT_CFLAGS)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl Web App Runtime
|
||||
dnl ========================================================
|
||||
MOZ_ARG_DISABLE_BOOL(webapp-runtime,
|
||||
[ --disable-webapp-runtime Disable Web App Runtime],
|
||||
MOZ_WEBAPP_RUNTIME=,
|
||||
MOZ_WEBAPP_RUNTIME=1)
|
||||
if test -n "$MOZ_WEBAPP_RUNTIME" -a "$OS_ARCH" = "WINNT"; then
|
||||
# Disable Web App Runtime for Windows builds that use the new toolkit if the
|
||||
# required major version and minimum minor version of Unicode NSIS isn't in
|
||||
# the path.
|
||||
REQ_NSIS_MAJOR_VER=2
|
||||
MIN_NSIS_MINOR_VER=33
|
||||
MOZ_PATH_PROGS(MAKENSISU, $MAKENSISU makensisu-2.46 makensisu makensis)
|
||||
if test -z "$MAKENSISU" -o "$MAKENSISU" = ":"; then
|
||||
AC_MSG_ERROR([To build the Web App Runtime you must have the latest MozillaBuild or Unicode NSIS with a major version of $REQ_NSIS_MAJOR_VER and a minimum minor version of $MIN_NSIS_MINOR_VER in your path. To build without the Web App Runtime reconfigure using --disable-webapp-runtime.])
|
||||
fi
|
||||
changequote(,)
|
||||
MAKENSISU_VER=`"$MAKENSISU" -version 2>/dev/null | sed -e '/-Unicode/!s/.*//g' -e 's/^v\([0-9]\+\.[0-9]\+\)\-Unicode$/\1/g'`
|
||||
changequote([,])
|
||||
if test ! "$MAKENSISU_VER" = ""; then
|
||||
MAKENSISU_MAJOR_VER=`echo $MAKENSISU_VER | $AWK -F\. '{ print $1 }'`
|
||||
MAKENSISU_MINOR_VER=`echo $MAKENSISU_VER | $AWK -F\. '{ print $2 }'`
|
||||
fi
|
||||
AC_MSG_CHECKING([for Unicode NSIS with major version == $REQ_NSIS_MAJOR_VER and minor version >= $MIN_NSIS_MINOR_VER])
|
||||
if test "$MAKENSISU_VER" = "" ||
|
||||
test ! "$MAKENSISU_MAJOR_VER" = "$REQ_NSIS_MAJOR_VER" -o \
|
||||
! "$MAKENSISU_MINOR_VER" -ge $MIN_NSIS_MINOR_VER; then
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([To build the Web App Runtime you must have the latest MozillaBuild or Unicode NSIS with a major version of $REQ_NSIS_MAJOR_VER and a minimum minor version of $MIN_NSIS_MINOR_VER in your path. To build without the Web App Runtime reconfigure using --disable-webapp-runtime.])
|
||||
fi
|
||||
AC_MSG_RESULT([yes])
|
||||
fi
|
||||
AC_SUBST(MOZ_WEBAPP_RUNTIME)
|
||||
if test "$MOZ_WEBAPP_RUNTIME"; then
|
||||
AC_DEFINE(MOZ_WEBAPP_RUNTIME)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl Installer
|
||||
dnl ========================================================
|
||||
|
|
|
@ -87,7 +87,7 @@ function CSPWarning(aMsg, aSource, aScriptSample, aLineNum) {
|
|||
|
||||
var consoleMsg = Components.classes["@mozilla.org/scripterror;1"]
|
||||
.createInstance(Components.interfaces.nsIScriptError);
|
||||
consoleMsg.init('CSP: ' + aMsg, aSource, aScriptSample, aLineNum, 0,
|
||||
consoleMsg.init(textMessage, aSource, aScriptSample, aLineNum, 0,
|
||||
Components.interfaces.nsIScriptError.warningFlag,
|
||||
"Content Security Policy");
|
||||
Components.classes["@mozilla.org/consoleservice;1"]
|
||||
|
@ -100,7 +100,7 @@ function CSPError(aMsg) {
|
|||
|
||||
var consoleMsg = Components.classes["@mozilla.org/scripterror;1"]
|
||||
.createInstance(Components.interfaces.nsIScriptError);
|
||||
consoleMsg.init('CSP: ' + aMsg, null, null, 0, 0,
|
||||
consoleMsg.init(textMessage, null, null, 0, 0,
|
||||
Components.interfaces.nsIScriptError.errorFlag,
|
||||
"Content Security Policy");
|
||||
Components.classes["@mozilla.org/consoleservice;1"]
|
||||
|
@ -213,7 +213,7 @@ CSPRep.ALLOW_DIRECTIVE = "allow";
|
|||
* @param aStr
|
||||
* string rep of a CSP
|
||||
* @param self (optional)
|
||||
* string or CSPSource representing the "self" source
|
||||
* URI representing the "self" source
|
||||
* @param docRequest (optional)
|
||||
* request for the parent document which may need to be suspended
|
||||
* while the policy-uri is asynchronously fetched
|
||||
|
@ -231,8 +231,6 @@ CSPRep.fromString = function(aStr, self, docRequest, csp) {
|
|||
var selfUri = null;
|
||||
if (self instanceof Components.interfaces.nsIURI)
|
||||
selfUri = self.clone();
|
||||
else if (self)
|
||||
selfUri = gIoService.newURI(self, null, null);
|
||||
|
||||
var dirs = aStr.split(";");
|
||||
|
||||
|
@ -452,8 +450,8 @@ CSPRep.prototype = {
|
|||
var dirs = [];
|
||||
|
||||
if (this._allowEval || this._allowInlineScripts) {
|
||||
dirs.push("options " + (this._allowEval ? "eval-script" : "")
|
||||
+ (this._allowInlineScripts ? "inline-script" : ""));
|
||||
dirs.push("options" + (this._allowEval ? " eval-script" : "")
|
||||
+ (this._allowInlineScripts ? " inline-script" : ""));
|
||||
}
|
||||
for (var i in this._directives) {
|
||||
if (this._directives[i]) {
|
||||
|
@ -604,7 +602,7 @@ function CSPSourceList() {
|
|||
* @param aStr
|
||||
* string rep of a CSP Source List
|
||||
* @param self (optional)
|
||||
* string or CSPSource representing the "self" source
|
||||
* URI or CSPSource representing the "self" source
|
||||
* @param enforceSelfChecks (optional)
|
||||
* if present, and "true", will check to be sure "self" has the
|
||||
* appropriate values to inherit when they are omitted from the source.
|
||||
|
@ -618,6 +616,12 @@ CSPSourceList.fromString = function(aStr, self, enforceSelfChecks) {
|
|||
// <source-list> ::= <source>
|
||||
// | <source-list>" "<source>
|
||||
|
||||
/* If self parameter is passed, convert to CSPSource,
|
||||
unless it is already a CSPSource. */
|
||||
if(self && !(self instanceof CSPSource)) {
|
||||
self = CSPSource.create(self);
|
||||
}
|
||||
|
||||
var slObj = new CSPSourceList();
|
||||
if (aStr === "'none'")
|
||||
return slObj;
|
||||
|
@ -810,6 +814,15 @@ function CSPSource() {
|
|||
* - nsURI
|
||||
* - string
|
||||
* - CSPSource (clone)
|
||||
* @param aData
|
||||
* string, nsURI, or CSPSource
|
||||
* @param self (optional)
|
||||
* if present, string, URI, or CSPSource representing the "self" resource
|
||||
* @param enforceSelfChecks (optional)
|
||||
* if present, and "true", will check to be sure "self" has the
|
||||
* appropriate values to inherit when they are omitted from the source.
|
||||
* @returns
|
||||
* an instance of CSPSource
|
||||
*/
|
||||
CSPSource.create = function(aData, self, enforceSelfChecks) {
|
||||
if (typeof aData === 'string')
|
||||
|
@ -912,7 +925,7 @@ CSPSource.fromURI = function(aURI, self, enforceSelfChecks) {
|
|||
* @param aStr
|
||||
* string rep of a CSP Source
|
||||
* @param self (optional)
|
||||
* string or CSPSource representing the "self" source
|
||||
* string, URI, or CSPSource representing the "self" source
|
||||
* @param enforceSelfChecks (optional)
|
||||
* if present, and "true", will check to be sure "self" has the
|
||||
* appropriate values to inherit when they are omitted from aURI.
|
||||
|
|
|
@ -239,8 +239,10 @@ ContentSecurityPolicy.prototype = {
|
|||
|
||||
// If there is a policy-uri, fetch the policy, then re-call this function.
|
||||
// (1) parse and create a CSPRep object
|
||||
// Note that we pass the full URI since when it's parsed as 'self' to construct a
|
||||
// CSPSource only the scheme, host, and port are kept.
|
||||
var newpolicy = CSPRep.fromString(aPolicy,
|
||||
selfURI.scheme + "://" + selfURI.hostPort,
|
||||
selfURI,
|
||||
this._docRequest,
|
||||
this);
|
||||
|
||||
|
|
|
@ -639,7 +639,13 @@ nsCORSListenerProxy::OnStopRequest(nsIRequest* aRequest,
|
|||
nsISupports* aContext,
|
||||
nsresult aStatusCode)
|
||||
{
|
||||
return mOuterListener->OnStopRequest(aRequest, aContext, aStatusCode);
|
||||
nsresult rv = mOuterListener->OnStopRequest(aRequest, aContext, aStatusCode);
|
||||
mOuterListener = nsnull;
|
||||
mOuterNotificationCallbacks = nsnull;
|
||||
mRedirectCallback = nsnull;
|
||||
mOldRedirectChannel = nsnull;
|
||||
mNewRedirectChannel = nsnull;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1026,6 +1032,9 @@ nsCORSPreflightListener::OnStopRequest(nsIRequest *aRequest,
|
|||
nsISupports *aContext,
|
||||
nsresult aStatus)
|
||||
{
|
||||
mOuterChannel = nsnull;
|
||||
mOuterListener = nsnull;
|
||||
mOuterContext = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -410,8 +410,9 @@ nsPlainTextSerializer::AppendElementEnd(Element* aElement,
|
|||
mOutputString = nsnull;
|
||||
|
||||
if (id == nsGkAtoms::head) {
|
||||
NS_ASSERTION(mHeadLevel != 0,
|
||||
"mHeadLevel being decremented below 0");
|
||||
--mHeadLevel;
|
||||
NS_ASSERTION(mHeadLevel >= 0, "mHeadLevel < 0");
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
|
|
@ -62,6 +62,9 @@
|
|||
#include "nsLayoutUtils.h"
|
||||
#include "nsTextFrame.h"
|
||||
#include "nsFontFaceList.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult);
|
||||
nsresult NS_NewContentSubtreeIterator(nsIContentIterator** aInstancePtrResult);
|
||||
|
@ -243,6 +246,9 @@ nsRange::~nsRange()
|
|||
{
|
||||
NS_ASSERTION(!IsInSelection(), "deleting nsRange that is in use");
|
||||
|
||||
// Maybe we can remove Detach() -- bug 702948.
|
||||
Telemetry::Accumulate(Telemetry::DOM_RANGE_DETACHED, mIsDetached);
|
||||
|
||||
// we want the side effects (releases and list removals)
|
||||
DoSetRange(nsnull, 0, nsnull, 0, nsnull);
|
||||
}
|
||||
|
|
|
@ -2502,6 +2502,7 @@ nsXMLHttpRequest::ChangeStateToDone()
|
|||
// methods/members will not throw.
|
||||
// This matches what IE does.
|
||||
mChannel = nsnull;
|
||||
mCORSPreflightChannel = nsnull;
|
||||
}
|
||||
else if (!(mState & XML_HTTP_REQUEST_GOT_FINAL_STOP)) {
|
||||
// We're a multipart request, so we're not done. Reset to opened.
|
||||
|
|
|
@ -10,14 +10,20 @@ const POLICY_URI_RELATIVE = "/policy";
|
|||
const DOCUMENT_URI = "http://localhost:" + POLICY_PORT + "/document";
|
||||
const CSP_DOC_BODY = "CSP doc content";
|
||||
const SD = CSPRep.SRC_DIRECTIVES;
|
||||
const MAX_TESTS = 2;
|
||||
var TESTS_COMPLETED = 0;
|
||||
|
||||
var cspr, cspr_static;
|
||||
// this will get populated by run_tests()
|
||||
var TESTS = [];
|
||||
|
||||
// helper to make URIs
|
||||
function mkuri(foo) {
|
||||
return Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService)
|
||||
.newURI(foo, null, null);
|
||||
}
|
||||
|
||||
// helper to use .equals on stuff
|
||||
function do_check_equivalent(foo, bar, stack) {
|
||||
if (!stack)
|
||||
if (!stack)
|
||||
stack = Components.stack.caller;
|
||||
|
||||
var text = foo + ".equals(" + bar + ")";
|
||||
|
@ -30,8 +36,10 @@ function do_check_equivalent(foo, bar, stack) {
|
|||
do_throw(text, stack);
|
||||
}
|
||||
|
||||
function listener() {
|
||||
function listener(csp, cspr_static) {
|
||||
this.buffer = "";
|
||||
this._csp = csp;
|
||||
this._cspr_static = cspr_static;
|
||||
}
|
||||
|
||||
listener.prototype = {
|
||||
|
@ -49,20 +57,30 @@ listener.prototype = {
|
|||
// make sure that we have the full document content, guaranteeing that
|
||||
// the document channel has been resumed, before we do the comparisons
|
||||
if (this.buffer == CSP_DOC_BODY) {
|
||||
// "policy-uri failed to load"
|
||||
|
||||
// need to re-grab cspr since it may have changed inside the document's
|
||||
// nsIContentSecurityPolicy instance. The problem is, this cspr_str is a
|
||||
// string and not a policy due to the way it's exposed from
|
||||
// nsIContentSecurityPolicy, so we have to re-parse it.
|
||||
let cspr_str = this._csp.policy;
|
||||
let cspr = CSPRep.fromString(cspr_str, mkuri(DOCUMENT_URI));
|
||||
|
||||
// and in reparsing it, we lose the 'self' relationships, so need to also
|
||||
// reparse the static one (or find a way to resolve 'self' in the parsed
|
||||
// policy when doing comparisons).
|
||||
let cspr_static_str = this._cspr_static.toString();
|
||||
let cspr_static_reparse = CSPRep.fromString(cspr_static_str, mkuri(DOCUMENT_URI));
|
||||
|
||||
// not null, and one policy .equals the other one
|
||||
do_check_neq(null, cspr);
|
||||
do_check_true(cspr.equals(cspr_static_reparse));
|
||||
|
||||
// other directives inherit self
|
||||
for (var i in SD) {
|
||||
do_check_equivalent(cspr._directives[SD[i]],
|
||||
cspr_static._directives[SD[i]]);
|
||||
}
|
||||
|
||||
do_test_finished();
|
||||
TESTS_COMPLETED++;
|
||||
// final teardown
|
||||
if (TESTS_COMPLETED == MAX_TESTS) {
|
||||
httpserv.stop(function(){});
|
||||
if (TESTS.length == 0) {
|
||||
httpserv.stop(do_test_finished);
|
||||
} else {
|
||||
do_test_finished();
|
||||
(TESTS.shift())();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,12 +91,11 @@ function run_test() {
|
|||
httpserv.registerPathHandler("/document", csp_doc_response);
|
||||
httpserv.registerPathHandler("/policy", csp_policy_response);
|
||||
httpserv.start(POLICY_PORT);
|
||||
TESTS = [ test_CSPRep_fromPolicyURI, test_CSPRep_fromRelativePolicyURI ];
|
||||
|
||||
var tests = [ test_CSPRep_fromPolicyURI, test_CSPRep_fromRelativePolicyURI];
|
||||
for (var i = 0 ; i < tests.length ; i++) {
|
||||
tests[i]();
|
||||
do_test_pending();
|
||||
}
|
||||
// when this triggers the "onStopRequest" callback, it'll
|
||||
// go to the next test.
|
||||
(TESTS.shift())();
|
||||
}
|
||||
|
||||
function makeChan(url) {
|
||||
|
@ -101,27 +118,41 @@ function csp_policy_response(metadata, response) {
|
|||
|
||||
///////////////////// TEST POLICY_URI //////////////////////
|
||||
function test_CSPRep_fromPolicyURI() {
|
||||
var csp = Components.classes["@mozilla.org/contentsecuritypolicy;1"]
|
||||
.createInstance[Components.interfaces.nsIContentSecurityPolicy];
|
||||
do_test_pending();
|
||||
let csp = Cc["@mozilla.org/contentsecuritypolicy;1"]
|
||||
.createInstance(Ci.nsIContentSecurityPolicy);
|
||||
// once the policy-uri is returned we will compare our static CSPRep with one
|
||||
// we generated from the content we got back from the network to make sure
|
||||
// they are equivalent
|
||||
cspr_static = CSPRep.fromString(POLICY_FROM_URI, DOCUMENT_URI);
|
||||
let cspr_static = CSPRep.fromString(POLICY_FROM_URI, mkuri(DOCUMENT_URI));
|
||||
|
||||
// simulates the request for the parent document
|
||||
var docChan = makeChan(DOCUMENT_URI);
|
||||
docChan.asyncOpen(new listener(), null);
|
||||
cspr = CSPRep.fromString("policy-uri " + POLICY_URI, DOCUMENT_URI, docChan, csp);
|
||||
docChan.asyncOpen(new listener(csp, cspr_static), null);
|
||||
|
||||
// the resulting policy here can be discarded, since it's going to be
|
||||
// "allow *"; when the policy-uri fetching call-back happens, the *real*
|
||||
// policy will be in csp.policy
|
||||
CSPRep.fromString("policy-uri " + POLICY_URI,
|
||||
mkuri(DOCUMENT_URI), docChan, csp);
|
||||
}
|
||||
|
||||
function test_CSPRep_fromRelativePolicyURI() {
|
||||
var csp = Components.classes["@mozilla.org/contentsecuritypolicy;1"]
|
||||
.createInstance[Components.interfaces.nsIContentSecurityPolicy];
|
||||
do_test_pending();
|
||||
let csp = Cc["@mozilla.org/contentsecuritypolicy;1"]
|
||||
.createInstance(Ci.nsIContentSecurityPolicy);
|
||||
// once the policy-uri is returned we will compare our static CSPRep with one
|
||||
// we generated from the content we got back from the network to make sure
|
||||
// they are equivalent
|
||||
cspr_static = CSPRep.fromString(POLICY_FROM_URI, DOCUMENT_URI);
|
||||
let cspr_static = CSPRep.fromString(POLICY_FROM_URI, mkuri(DOCUMENT_URI));
|
||||
|
||||
// simulates the request for the parent document
|
||||
var docChan = makeChan(DOCUMENT_URI);
|
||||
docChan.asyncOpen(new listener(), null);
|
||||
cspr = CSPRep.fromString("policy-uri " + POLICY_URI_RELATIVE, DOCUMENT_URI, docChan, csp);
|
||||
docChan.asyncOpen(new listener(csp, cspr_static), null);
|
||||
|
||||
// the resulting policy here can be discarded, since it's going to be
|
||||
// "allow *"; when the policy-uri fetching call-back happens, the *real*
|
||||
// policy will be in csp.policy
|
||||
CSPRep.fromString("policy-uri " + POLICY_URI_RELATIVE,
|
||||
mkuri(DOCUMENT_URI), docChan, csp);
|
||||
}
|
||||
|
|
|
@ -47,6 +47,14 @@ const POLICY_PORT = 9000;
|
|||
const POLICY_URI = "http://localhost:" + POLICY_PORT + "/policy";
|
||||
const POLICY_URI_RELATIVE = "/policy";
|
||||
|
||||
//converts string to nsIURI
|
||||
function URI(uriString) {
|
||||
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
return ioService.newURI(uriString, null, null);
|
||||
}
|
||||
|
||||
|
||||
// helper to assert that an array has the given value somewhere.
|
||||
function do_check_in_array(arr, val, stack) {
|
||||
if (!stack)
|
||||
|
@ -272,7 +280,7 @@ test(
|
|||
function test_CSPSourceList_fromString_twohost() {
|
||||
var str = "foo.bar:21 https://ras.bar";
|
||||
var parsed = "http://foo.bar:21 https://ras.bar:443";
|
||||
var sd = CSPSourceList.fromString(str, "http://self.com:80");
|
||||
var sd = CSPSourceList.fromString(str, URI("http://self.com:80"));
|
||||
//"two-host list should parse"
|
||||
do_check_neq(null,sd);
|
||||
//"two-host list should parse to two hosts"
|
||||
|
@ -284,9 +292,9 @@ test(
|
|||
test(
|
||||
function test_CSPSourceList_permits() {
|
||||
var nullSourceList = CSPSourceList.fromString("'none'");
|
||||
var simpleSourceList = CSPSourceList.fromString("a.com", "http://self.com");
|
||||
var simpleSourceList = CSPSourceList.fromString("a.com", URI("http://self.com"));
|
||||
var doubleSourceList = CSPSourceList.fromString("https://foo.com http://bar.com:88",
|
||||
"http://self.com:88");
|
||||
URI("http://self.com:88"));
|
||||
var allSourceList = CSPSourceList.fromString("*");
|
||||
|
||||
//'none' should permit none."
|
||||
|
@ -362,7 +370,7 @@ test(
|
|||
var SD = CSPRep.SRC_DIRECTIVES;
|
||||
|
||||
// check default policy "allow *"
|
||||
cspr = CSPRep.fromString("allow *", "http://self.com:80");
|
||||
cspr = CSPRep.fromString("allow *", URI("http://self.com:80"));
|
||||
// "DEFAULT_SRC directive is missing when specified in fromString"
|
||||
do_check_has_key(cspr._directives, SD.DEFAULT_SRC);
|
||||
|
||||
|
@ -384,7 +392,7 @@ test(
|
|||
var SD = CSPRep.SRC_DIRECTIVES;
|
||||
|
||||
// apply policy of "default-src *" (e.g. "allow *")
|
||||
cspr = CSPRep.fromString("default-src *", "http://self.com:80");
|
||||
cspr = CSPRep.fromString("default-src *", URI("http://self.com:80"));
|
||||
// "DEFAULT_SRC directive is missing when specified in fromString"
|
||||
do_check_has_key(cspr._directives, SD.DEFAULT_SRC);
|
||||
|
||||
|
@ -399,8 +407,8 @@ test(
|
|||
|
||||
// check that |allow *| and |default-src *| are parsed equivalently and
|
||||
// result in the same set of explicit policy directives
|
||||
cspr = CSPRep.fromString("default-src *", "http://self.com:80");
|
||||
cspr_allow = CSPRep.fromString("allow *", "http://self.com:80");
|
||||
cspr = CSPRep.fromString("default-src *", URI("http://self.com:80"));
|
||||
cspr_allow = CSPRep.fromString("allow *", URI("http://self.com:80"));
|
||||
|
||||
for (var d in SD) {
|
||||
do_check_equivalent(cspr._directives[SD[d]],
|
||||
|
@ -418,7 +426,7 @@ test(
|
|||
|
||||
// check one-directive policies
|
||||
cspr = CSPRep.fromString("allow bar.com; script-src https://foo.com",
|
||||
"http://self.com");
|
||||
URI("http://self.com"));
|
||||
|
||||
for(var x in DEFAULTS) {
|
||||
//DEFAULTS[x] + " does not use default rule."
|
||||
|
@ -446,7 +454,7 @@ test(
|
|||
var polstr = "allow allow.com; "
|
||||
+ "script-src https://foo.com; "
|
||||
+ "img-src bar.com:*";
|
||||
cspr = CSPRep.fromString(polstr, "http://self.com");
|
||||
cspr = CSPRep.fromString(polstr, URI("http://self.com"));
|
||||
|
||||
for(var x in DEFAULTS) {
|
||||
do_check_true(cspr.permits("http://allow.com", DEFAULTS[x]));
|
||||
|
@ -478,7 +486,7 @@ test(function test_CSPRep_fromString_withself() {
|
|||
|
||||
// check one-directive policies
|
||||
cspr = CSPRep.fromString("allow 'self'; script-src 'self' https://*:*",
|
||||
self);
|
||||
URI(self));
|
||||
//"img-src does not enforce default rule, 'self'.
|
||||
do_check_false(cspr.permits("https://foo.com:400", SD.IMG_SRC));
|
||||
//"img-src does not allow self
|
||||
|
@ -498,7 +506,7 @@ test(function test_FrameAncestor_defaults() {
|
|||
var SD = CSPRep.SRC_DIRECTIVES;
|
||||
var self = "http://self.com:34";
|
||||
|
||||
cspr = CSPRep.fromString("allow 'none'", self);
|
||||
cspr = CSPRep.fromString("allow 'none'", URI(self));
|
||||
|
||||
//"frame-ancestors should default to * not 'allow' value"
|
||||
do_check_true(cspr.permits("https://foo.com:400", SD.FRAME_ANCESTORS));
|
||||
|
@ -507,7 +515,7 @@ test(function test_FrameAncestor_defaults() {
|
|||
do_check_true(cspr.permits("http://self.com", SD.FRAME_ANCESTORS));
|
||||
do_check_true(cspr.permits("http://subd.self.com:34", SD.FRAME_ANCESTORS));
|
||||
|
||||
cspr = CSPRep.fromString("allow 'none'; frame-ancestors 'self'", self);
|
||||
cspr = CSPRep.fromString("allow 'none'; frame-ancestors 'self'", URI(self));
|
||||
|
||||
//"frame-ancestors should only allow self"
|
||||
do_check_true(cspr.permits("http://self.com:34", SD.FRAME_ANCESTORS));
|
||||
|
@ -531,27 +539,27 @@ test(function test_CSP_ReportURI_parsing() {
|
|||
var uri_valid_relative2_expanded = self + "/" + uri_valid_relative2;
|
||||
var uri_invalid_relative = "javascript:alert(1)";
|
||||
|
||||
cspr = CSPRep.fromString("allow *; report-uri " + uri_valid_absolute, self);
|
||||
cspr = CSPRep.fromString("allow *; report-uri " + uri_valid_absolute, URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
do_check_in_array(parsedURIs, uri_valid_absolute);
|
||||
do_check_eq(parsedURIs.length, 1);
|
||||
|
||||
cspr = CSPRep.fromString("allow *; report-uri " + uri_invalid_host_absolute, self);
|
||||
cspr = CSPRep.fromString("allow *; report-uri " + uri_invalid_host_absolute, URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
do_check_in_array(parsedURIs, "");
|
||||
do_check_eq(parsedURIs.length, 1); // the empty string is in there.
|
||||
|
||||
cspr = CSPRep.fromString("allow *; report-uri " + uri_invalid_relative, self);
|
||||
cspr = CSPRep.fromString("allow *; report-uri " + uri_invalid_relative, URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
do_check_in_array(parsedURIs, "");
|
||||
do_check_eq(parsedURIs.length, 1);
|
||||
|
||||
cspr = CSPRep.fromString("allow *; report-uri " + uri_valid_relative, self);
|
||||
cspr = CSPRep.fromString("allow *; report-uri " + uri_valid_relative, URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
do_check_in_array(parsedURIs, uri_valid_relative_expanded);
|
||||
do_check_eq(parsedURIs.length, 1);
|
||||
|
||||
cspr = CSPRep.fromString("allow *; report-uri " + uri_valid_relative2, self);
|
||||
cspr = CSPRep.fromString("allow *; report-uri " + uri_valid_relative2, URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
dump(parsedURIs.length);
|
||||
do_check_in_array(parsedURIs, uri_valid_relative2_expanded);
|
||||
|
@ -560,7 +568,7 @@ test(function test_CSP_ReportURI_parsing() {
|
|||
// combination!
|
||||
cspr = CSPRep.fromString("allow *; report-uri " +
|
||||
uri_valid_relative2 + " " +
|
||||
uri_valid_absolute, self);
|
||||
uri_valid_absolute, URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
do_check_in_array(parsedURIs, uri_valid_relative2_expanded);
|
||||
do_check_in_array(parsedURIs, uri_valid_absolute);
|
||||
|
@ -569,7 +577,7 @@ test(function test_CSP_ReportURI_parsing() {
|
|||
cspr = CSPRep.fromString("allow *; report-uri " +
|
||||
uri_valid_relative2 + " " +
|
||||
uri_invalid_host_absolute + " " +
|
||||
uri_valid_absolute, self);
|
||||
uri_valid_absolute, URI(self));
|
||||
parsedURIs = cspr.getReportURIs().split(/\s+/);
|
||||
do_check_in_array(parsedURIs, uri_valid_relative2_expanded);
|
||||
do_check_in_array(parsedURIs, uri_valid_absolute);
|
||||
|
@ -631,11 +639,11 @@ test(function test_CSPRep_fromPolicyURI_failswhenmixed() {
|
|||
var my_uri_policy = "policy-uri " + POLICY_URI;
|
||||
|
||||
//print(" --- Ignore the following two errors if they print ---");
|
||||
cspr = CSPRep.fromString("allow *; " + my_uri_policy, self);
|
||||
cspr = CSPRep.fromString("allow *; " + my_uri_policy, URI(self));
|
||||
|
||||
//"Parsing should fail when 'policy-uri' is mixed with allow directive"
|
||||
do_check_equivalent(cspr, closed_policy);
|
||||
cspr = CSPRep.fromString("img-src 'self'; " + my_uri_policy, self);
|
||||
cspr = CSPRep.fromString("img-src 'self'; " + my_uri_policy, URI(self));
|
||||
|
||||
//"Parsing should fail when 'policy-uri' is mixed with other directives"
|
||||
do_check_equivalent(cspr, closed_policy);
|
||||
|
|
|
@ -58,49 +58,89 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=408231
|
|||
["unlink", "true"],
|
||||
["not-a-command", "false"]
|
||||
];
|
||||
|
||||
var commandStateResults = [
|
||||
["contentReadOnly", "exception"],
|
||||
["copy", "exception"],
|
||||
["createlink", "exception"],
|
||||
["cut", "exception"],
|
||||
["decreasefontsize", "exception"],
|
||||
["delete", "exception"],
|
||||
["fontname", "exception"],
|
||||
["fontsize", "exception"],
|
||||
["formatblock", "exception"],
|
||||
["heading", "exception"],
|
||||
["hilitecolor", "exception"],
|
||||
["increasefontsize", "exception"],
|
||||
["indent", "exception"],
|
||||
["inserthorizontalrule", "exception"],
|
||||
["inserthtml", "exception"],
|
||||
["insertimage", "exception"],
|
||||
|
||||
var commandIndetermResults = [
|
||||
["contentReadOnly", "false"],
|
||||
["copy", "false"],
|
||||
["createlink", "false"],
|
||||
["cut", "false"],
|
||||
["decreasefontsize", "false"],
|
||||
["delete", "false"],
|
||||
["fontname", "false"],
|
||||
["fontsize", "false"],
|
||||
["formatblock", "false"],
|
||||
["heading", "false"],
|
||||
["hilitecolor", "false"],
|
||||
["increasefontsize", "false"],
|
||||
["indent", "false"],
|
||||
["inserthorizontalrule", "false"],
|
||||
["inserthtml", "false"],
|
||||
["insertimage", "false"],
|
||||
["insertorderedlist", "false"],
|
||||
["insertunorderedlist", "false"],
|
||||
["insertparagraph", "exception"],
|
||||
["insertparagraph", "false"],
|
||||
["italic", "false"],
|
||||
["justifycenter", "false"],
|
||||
["justifyfull", "false"],
|
||||
["justifyleft", "true"],
|
||||
["justifyleft", "false"],
|
||||
["justifyright", "false"],
|
||||
["outdent", "exception"],
|
||||
//["paste", "exception"],
|
||||
["redo", "exception"],
|
||||
["removeformat", "exception"],
|
||||
["selectall", "exception"],
|
||||
["outdent", "false"],
|
||||
//["paste", "false"],
|
||||
["redo", "false"],
|
||||
["removeformat", "false"],
|
||||
["selectall", "false"],
|
||||
["strikethrough", "false"],
|
||||
["styleWithCSS", "false"],
|
||||
["subscript", "false"],
|
||||
["superscript", "false"],
|
||||
["underline", "false"],
|
||||
["undo", "exception"],
|
||||
["undo", "false"],
|
||||
["unlink", "false"],
|
||||
["not-a-command", "exception"]
|
||||
["not-a-command", "NS_ERROR_NOT_IMPLEMENTED"]
|
||||
];
|
||||
|
||||
var commandStateResults = [
|
||||
["contentReadOnly", "false"],
|
||||
["copy", "false"],
|
||||
["createlink", "false"],
|
||||
["cut", "false"],
|
||||
["decreasefontsize", "false"],
|
||||
["delete", "false"],
|
||||
["fontname", "false"],
|
||||
["fontsize", "false"],
|
||||
["formatblock", "false"],
|
||||
["heading", "false"],
|
||||
["hilitecolor", "false"],
|
||||
["increasefontsize", "false"],
|
||||
["indent", "false"],
|
||||
["inserthorizontalrule", "false"],
|
||||
["inserthtml", "false"],
|
||||
["insertimage", "false"],
|
||||
["insertorderedlist", "false"],
|
||||
["insertunorderedlist", "false"],
|
||||
["insertparagraph", "false"],
|
||||
["italic", "false"],
|
||||
["justifycenter", "false"],
|
||||
["justifyfull", "false"],
|
||||
["justifyleft", "true"],
|
||||
["justifyright", "false"],
|
||||
["outdent", "false"],
|
||||
//["paste", "false"],
|
||||
["redo", "false"],
|
||||
["removeformat", "false"],
|
||||
["selectall", "false"],
|
||||
["strikethrough", "false"],
|
||||
["styleWithCSS", "false"],
|
||||
["subscript", "false"],
|
||||
["superscript", "false"],
|
||||
["underline", "false"],
|
||||
["undo", "false"],
|
||||
["unlink", "false"],
|
||||
["not-a-command", "NS_ERROR_NOT_IMPLEMENTED"]
|
||||
];
|
||||
|
||||
var commandValueResults = [
|
||||
["contentReadOnly", "exception"],
|
||||
["contentReadOnly", ""],
|
||||
["copy", ""],
|
||||
["createlink", ""],
|
||||
["cut", ""],
|
||||
|
@ -136,7 +176,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=408231
|
|||
["underline", ""],
|
||||
["undo", ""],
|
||||
["unlink", ""],
|
||||
["not-a-command", "exception"],
|
||||
["not-a-command", "NS_ERROR_NOT_IMPLEMENTED"],
|
||||
];
|
||||
|
||||
|
||||
|
@ -145,7 +185,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=408231
|
|||
try {
|
||||
result = '' + document.queryCommandEnabled( cmdName );
|
||||
} catch( error ) {
|
||||
result = 'exception';
|
||||
result = 'name' in error ? error.name : 'exception';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function callQueryCommandIndeterm(cmdName) {
|
||||
var result;
|
||||
try {
|
||||
result = '' + document.queryCommandIndeterm( cmdName );
|
||||
} catch( error ) {
|
||||
result = 'name' in error ? error.name : 'exception';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -155,7 +205,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=408231
|
|||
try {
|
||||
result = '' + document.queryCommandState( cmdName );
|
||||
} catch( error ) {
|
||||
result = 'exception';
|
||||
result = 'name' in error ? error.name : 'exception';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -165,7 +215,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=408231
|
|||
try {
|
||||
result = '' + document.queryCommandValue( cmdName );
|
||||
} catch( error ) {
|
||||
result = 'exception';
|
||||
result = 'name' in error ? error.name : 'exception';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -183,6 +233,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=408231
|
|||
document.designMode='on';
|
||||
window.getSelection().collapse(document.body, 0);
|
||||
testQueryCommand(commandEnabledResults, callQueryCommandEnabled, "queryCommandEnabled");
|
||||
testQueryCommand(commandIndetermResults, callQueryCommandIndeterm, "queryCommandIndeterm");
|
||||
testQueryCommand(commandStateResults, callQueryCommandState, "queryCommandState");
|
||||
testQueryCommand(commandValueResults, callQueryCommandValue, "queryCommandValue");
|
||||
document.designMode='off';
|
||||
|
|
|
@ -2818,7 +2818,7 @@ static const struct MidasCommand gMidasCommandTable[] = {
|
|||
{ "redo", "cmd_redo", "", true, false },
|
||||
{ "indent", "cmd_indent", "", true, false },
|
||||
{ "outdent", "cmd_outdent", "", true, false },
|
||||
{ "backcolor", "cmd_backgroundColor", "", false, false },
|
||||
{ "backcolor", "cmd_highlight", "", false, false },
|
||||
{ "forecolor", "cmd_fontColor", "", false, false },
|
||||
{ "hilitecolor", "cmd_highlight", "", false, false },
|
||||
{ "fontname", "cmd_fontFace", "", false, false },
|
||||
|
@ -2953,7 +2953,9 @@ ConvertToMidasInternalCommandInner(const nsAString & inCommandID,
|
|||
}
|
||||
}
|
||||
|
||||
return j != ArrayLength(gBlocks);
|
||||
if (j == ArrayLength(gBlocks)) {
|
||||
outParam.Truncate();
|
||||
}
|
||||
}
|
||||
else {
|
||||
CopyUTF16toUTF8(inParam, outParam);
|
||||
|
@ -3101,6 +3103,11 @@ nsHTMLDocument::ExecCommand(const nsAString & commandID,
|
|||
cmdToDispatch, paramStr, isBool, boolVal))
|
||||
return NS_OK;
|
||||
|
||||
if (cmdToDispatch.EqualsLiteral("cmd_paragraphState") && paramStr.IsEmpty()) {
|
||||
// Invalid value
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!isBool && paramStr.IsEmpty()) {
|
||||
rv = cmdMgr->DoCommand(cmdToDispatch.get(), nsnull, window);
|
||||
} else {
|
||||
|
@ -3179,10 +3186,8 @@ nsHTMLDocument::QueryCommandIndeterm(const nsAString & commandID,
|
|||
if (!window)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCAutoString cmdToDispatch, paramToCheck;
|
||||
bool dummy;
|
||||
if (!ConvertToMidasInternalCommand(commandID, commandID,
|
||||
cmdToDispatch, paramToCheck, dummy, dummy))
|
||||
nsCAutoString cmdToDispatch;
|
||||
if (!ConvertToMidasInternalCommand(commandID, cmdToDispatch))
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
nsresult rv;
|
||||
|
@ -3194,10 +3199,11 @@ nsHTMLDocument::QueryCommandIndeterm(const nsAString & commandID,
|
|||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// if command does not have a state_mixed value, this call fails, so we fail too,
|
||||
// which is what is expected
|
||||
rv = cmdParams->GetBooleanValue("state_mixed", _retval);
|
||||
return rv;
|
||||
// If command does not have a state_mixed value, this call fails and sets
|
||||
// *_retval to false. This is fine -- we want to return false in that case
|
||||
// anyway (bug 738385), so we just return NS_OK regardless.
|
||||
cmdParams->GetBooleanValue("state_mixed", _retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* boolean queryCommandState(in DOMString commandID); */
|
||||
|
@ -3258,14 +3264,14 @@ nsHTMLDocument::QueryCommandState(const nsAString & commandID, bool *_retval)
|
|||
}
|
||||
if (actualAlignmentType)
|
||||
nsMemory::Free(actualAlignmentType);
|
||||
}
|
||||
else {
|
||||
rv = cmdParams->GetBooleanValue("state_all", _retval);
|
||||
if (NS_FAILED(rv))
|
||||
*_retval = false;
|
||||
return rv;
|
||||
}
|
||||
|
||||
return rv;
|
||||
// If command does not have a state_all value, this call fails and sets
|
||||
// *_retval to false. This is fine -- we want to return false in that case
|
||||
// anyway (bug 738385), so we just return NS_OK regardless.
|
||||
cmdParams->GetBooleanValue("state_all", _retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* boolean queryCommandSupported(in DOMString commandID); */
|
||||
|
@ -3347,12 +3353,16 @@ nsHTMLDocument::QueryCommandValue(const nsAString & commandID,
|
|||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// If command does not have a state_attribute value, this call fails, and
|
||||
// _retval will wind up being the empty string. This is fine -- we want to
|
||||
// return "" in that case anyway (bug 738385), so we just return NS_OK
|
||||
// regardless.
|
||||
nsXPIDLCString cStringResult;
|
||||
rv = cmdParams->GetCStringValue("state_attribute",
|
||||
getter_Copies(cStringResult));
|
||||
cmdParams->GetCStringValue("state_attribute",
|
||||
getter_Copies(cStringResult));
|
||||
CopyUTF8toUTF16(cStringResult, _retval);
|
||||
|
||||
return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -12,6 +12,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
const WEBAPP_RUNTIME = Services.appinfo.ID == "webapprt@mozilla.org";
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
return NetUtil;
|
||||
|
@ -24,7 +26,10 @@ XPCOMUtils.defineLazyGetter(this, "ppmm", function() {
|
|||
#ifdef MOZ_WIDGET_GONK
|
||||
const DIRECTORY_NAME = "webappsDir";
|
||||
#else
|
||||
const DIRECTORY_NAME = "ProfD";
|
||||
// If we're executing in the context of the webapp runtime, the data files
|
||||
// are in a different directory (currently the Firefox profile that installed
|
||||
// the webapp); otherwise, they're in the current profile.
|
||||
const DIRECTORY_NAME = WEBAPP_RUNTIME ? "WebappRegD" : "ProfD";
|
||||
#endif
|
||||
|
||||
let DOMApplicationRegistry = {
|
||||
|
|
|
@ -143,9 +143,7 @@ AudioRunnable::Run()
|
|||
if (!jenv)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (jenv->PushLocalFrame(128)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mozilla::AndroidBridge::AutoLocalJNIFrame autoFrame(jenv);
|
||||
|
||||
jbyteArray bytearray = jenv->NewByteArray(mTrack->bufferSize);
|
||||
if (!bytearray) {
|
||||
|
@ -201,7 +199,6 @@ AudioRunnable::Run()
|
|||
free(mTrack);
|
||||
|
||||
jenv->ReleaseByteArrayElements(bytearray, byte, 0);
|
||||
jenv->PopLocalFrame(NULL);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -914,8 +914,8 @@ nsHighlightColorStateCommand::SetState(nsIEditor *aEditor, nsString& newState)
|
|||
// rv = RemoveOneProperty(htmlEditor, NS_LITERAL_STRING("font"), NS_LITERAL_STRING("bgcolor"));
|
||||
rv = htmlEditor->RemoveInlineProperty(fontAtom, NS_LITERAL_STRING("bgcolor"));
|
||||
} else {
|
||||
rv = htmlEditor->SetCSSInlineProperty(fontAtom, NS_LITERAL_STRING("bgcolor"),
|
||||
newState);
|
||||
rv = htmlEditor->SetInlineProperty(fontAtom, NS_LITERAL_STRING("bgcolor"),
|
||||
newState);
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
|
|
@ -52,7 +52,7 @@ interface nsIContentFilter;
|
|||
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_EDITOR, 1)
|
||||
|
||||
%}
|
||||
[scriptable, uuid(FF67AD39-ED58-4CD1-A1A3-DCD988390A97)]
|
||||
[scriptable, uuid(833f30de-94c7-4630-a852-2300ef329d7b)]
|
||||
|
||||
interface nsIHTMLEditor : nsISupports
|
||||
{
|
||||
|
@ -118,9 +118,6 @@ interface nsIHTMLEditor : nsISupports
|
|||
* Example: aProperty="font", aAttribute="color",
|
||||
* aValue="0x00FFFF"
|
||||
*/
|
||||
void setCSSInlineProperty(in nsIAtom aProperty,
|
||||
in AString aAttribute,
|
||||
in AString aValue);
|
||||
void setInlineProperty(in nsIAtom aProperty,
|
||||
in AString aAttribute,
|
||||
in AString aValue);
|
||||
|
|
|
@ -109,18 +109,6 @@ NS_IMETHODIMP nsHTMLEditor::RemoveAllDefaultProperties()
|
|||
}
|
||||
|
||||
|
||||
// Add the CSS style corresponding to the HTML inline style defined
|
||||
// by aProperty aAttribute and aValue to the selection
|
||||
NS_IMETHODIMP nsHTMLEditor::SetCSSInlineProperty(nsIAtom *aProperty,
|
||||
const nsAString & aAttribute,
|
||||
const nsAString & aValue)
|
||||
{
|
||||
if (IsCSSEnabled()) {
|
||||
return SetInlineProperty(aProperty, aAttribute, aValue);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsHTMLEditor::SetInlineProperty(nsIAtom *aProperty,
|
||||
const nsAString & aAttribute,
|
||||
const nsAString & aValue)
|
||||
|
@ -385,60 +373,58 @@ nsHTMLEditor::SetInlinePropertyOnNode( nsIDOMNode *aNode,
|
|||
nsAutoString tag;
|
||||
aProperty->ToString(tag);
|
||||
ToLowerCase(tag);
|
||||
|
||||
if (IsCSSEnabled())
|
||||
{
|
||||
// we are in CSS mode
|
||||
if (mHTMLCSSUtils->IsCSSEditableProperty(aNode, aProperty, aAttribute))
|
||||
{
|
||||
// the HTML style defined by aProperty/aAttribute has a CSS equivalence
|
||||
// in this implementation for the node aNode
|
||||
nsCOMPtr<nsIDOMNode> tmp = aNode;
|
||||
if (IsTextNode(tmp))
|
||||
{
|
||||
// we are working on a text node and need to create a span container
|
||||
// that will carry the styles
|
||||
InsertContainerAbove( aNode,
|
||||
address_of(tmp),
|
||||
NS_LITERAL_STRING("span"),
|
||||
nsnull,
|
||||
nsnull);
|
||||
}
|
||||
nsCOMPtr<nsIDOMElement>element;
|
||||
element = do_QueryInterface(tmp);
|
||||
// first we have to remove occurences of the same style hint in the
|
||||
// children of the aNode
|
||||
res = RemoveStyleInside(tmp, aProperty, aAttribute, true);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
PRInt32 count;
|
||||
// then we add the css styles corresponding to the HTML style request
|
||||
res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, aProperty, aAttribute, aValue, &count, false);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> nextSibling, previousSibling;
|
||||
GetNextHTMLSibling(tmp, address_of(nextSibling));
|
||||
GetPriorHTMLSibling(tmp, address_of(previousSibling));
|
||||
if (nextSibling || previousSibling)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> mergeParent;
|
||||
res = tmp->GetParentNode(getter_AddRefs(mergeParent));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
if (previousSibling &&
|
||||
nsEditor::NodeIsType(previousSibling, nsEditProperty::span) &&
|
||||
NodesSameType(tmp, previousSibling))
|
||||
{
|
||||
res = JoinNodes(previousSibling, tmp, mergeParent);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
}
|
||||
if (nextSibling &&
|
||||
nsEditor::NodeIsType(nextSibling, nsEditProperty::span) &&
|
||||
NodesSameType(tmp, nextSibling))
|
||||
{
|
||||
res = JoinNodes(tmp, nextSibling, mergeParent);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
bool useCSS = (IsCSSEnabled() &&
|
||||
mHTMLCSSUtils->IsCSSEditableProperty(aNode, aProperty, aAttribute)) ||
|
||||
// bgcolor is always done using CSS
|
||||
aAttribute->EqualsLiteral("bgcolor");
|
||||
|
||||
if (useCSS) {
|
||||
nsCOMPtr<nsIDOMNode> tmp = aNode;
|
||||
if (IsTextNode(tmp))
|
||||
{
|
||||
// we are working on a text node and need to create a span container
|
||||
// that will carry the styles
|
||||
InsertContainerAbove(aNode,
|
||||
address_of(tmp),
|
||||
NS_LITERAL_STRING("span"),
|
||||
nsnull,
|
||||
nsnull);
|
||||
}
|
||||
nsCOMPtr<nsIDOMElement>element;
|
||||
element = do_QueryInterface(tmp);
|
||||
// first we have to remove occurences of the same style hint in the
|
||||
// children of the aNode
|
||||
res = RemoveStyleInside(tmp, aProperty, aAttribute, true);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
PRInt32 count;
|
||||
// then we add the css styles corresponding to the HTML style request
|
||||
res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, aProperty, aAttribute, aValue, &count, false);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> nextSibling, previousSibling;
|
||||
GetNextHTMLSibling(tmp, address_of(nextSibling));
|
||||
GetPriorHTMLSibling(tmp, address_of(previousSibling));
|
||||
if (nextSibling || previousSibling)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> mergeParent;
|
||||
res = tmp->GetParentNode(getter_AddRefs(mergeParent));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
if (previousSibling &&
|
||||
nsEditor::NodeIsType(previousSibling, nsEditProperty::span) &&
|
||||
NodesSameType(tmp, previousSibling))
|
||||
{
|
||||
res = JoinNodes(previousSibling, tmp, mergeParent);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
}
|
||||
if (nextSibling &&
|
||||
nsEditor::NodeIsType(nextSibling, nsEditProperty::span) &&
|
||||
NodesSameType(tmp, nextSibling))
|
||||
{
|
||||
res = JoinNodes(tmp, nextSibling, mergeParent);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// don't need to do anything if property already set on node
|
||||
|
|
|
@ -18,11 +18,8 @@ var knownFailures = {
|
|||
'0-undefined' : true
|
||||
},
|
||||
'a' : {
|
||||
'backcolor-0' : true,
|
||||
'backcolor-1' : true,
|
||||
'createbookmark-0' : true,
|
||||
'fontsize-1' : true,
|
||||
'hilitecolor-0' : true,
|
||||
'subscript-1' : true,
|
||||
'superscript-1' : true,
|
||||
},
|
||||
|
@ -35,16 +32,10 @@ var knownFailures = {
|
|||
'unbookmark-0' : true,
|
||||
},
|
||||
'q': {
|
||||
'backcolor-0' : true,
|
||||
'backcolor-1' : true,
|
||||
'backcolor-2' : true,
|
||||
'fontsize-1' : true,
|
||||
'fontsize-2' : true,
|
||||
},
|
||||
'c': {
|
||||
'backcolor-0' : true,
|
||||
'backcolor-1' : true,
|
||||
'backcolor-2' : true,
|
||||
'fontname-0' : true,
|
||||
'fontname-2' : true,
|
||||
'fontname-3' : true,
|
||||
|
|
|
@ -1893,26 +1893,18 @@ nsTextServicesDocument::DidJoinNodes(nsIDOMNode *aLeftNode,
|
|||
// fflush(stdout);
|
||||
//**** KDEBUG ****
|
||||
|
||||
// Make sure that both nodes are text nodes!
|
||||
// Make sure that both nodes are text nodes -- otherwise we don't care.
|
||||
|
||||
result = aLeftNode->GetNodeType(&type);
|
||||
|
||||
NS_ENSURE_SUCCESS(result, false);
|
||||
|
||||
if (nsIDOMNode::TEXT_NODE != type)
|
||||
{
|
||||
NS_ERROR("JoinNode called with a non-text left node!");
|
||||
return NS_ERROR_FAILURE;
|
||||
if (nsIDOMNode::TEXT_NODE != type) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
result = aRightNode->GetNodeType(&type);
|
||||
|
||||
NS_ENSURE_SUCCESS(result, false);
|
||||
|
||||
if (nsIDOMNode::TEXT_NODE != type)
|
||||
{
|
||||
NS_ERROR("JoinNode called with a non-text right node!");
|
||||
return NS_ERROR_FAILURE;
|
||||
if (nsIDOMNode::TEXT_NODE != type) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Note: The editor merges the contents of the left node into the
|
||||
|
|
|
@ -231,23 +231,6 @@ CompositorParent::Composite()
|
|||
#endif
|
||||
}
|
||||
|
||||
// Go down shadow layer tree, setting properties to match their non-shadow
|
||||
// counterparts.
|
||||
static void
|
||||
SetShadowProperties(Layer* aLayer)
|
||||
{
|
||||
// FIXME: Bug 717688 -- Do these updates in ShadowLayersParent::RecvUpdate.
|
||||
ShadowLayer* shadow = aLayer->AsShadowLayer();
|
||||
shadow->SetShadowTransform(aLayer->GetTransform());
|
||||
shadow->SetShadowVisibleRegion(aLayer->GetVisibleRegion());
|
||||
shadow->SetShadowClipRect(aLayer->GetClipRect());
|
||||
|
||||
for (Layer* child = aLayer->GetFirstChild();
|
||||
child; child = child->GetNextSibling()) {
|
||||
SetShadowProperties(child);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
// Do a breadth-first search to find the first layer in the tree that is
|
||||
// scrollable.
|
||||
|
@ -256,21 +239,6 @@ CompositorParent::GetPrimaryScrollableLayer()
|
|||
{
|
||||
Layer* root = mLayerManager->GetRoot();
|
||||
|
||||
// FIXME: We're currently getting passed layers that are not part of our content, but
|
||||
// we are drawing them anyway. This is causing severe rendering corruption to our background
|
||||
// and checkerboarding. The real fix here is to assert that we don't have any useless layers
|
||||
// and ensure that layout isn't giving us any. This is being tracked in bug 728284.
|
||||
// For now just clip them to the empty rect so we don't draw them.
|
||||
Layer* discardLayer = root->GetFirstChild();
|
||||
|
||||
while (discardLayer) {
|
||||
if (!discardLayer->AsContainerLayer()) {
|
||||
discardLayer->IntersectClipRect(nsIntRect());
|
||||
SetShadowProperties(discardLayer);
|
||||
}
|
||||
discardLayer = discardLayer->GetNextSibling();
|
||||
}
|
||||
|
||||
nsTArray<Layer*> queue;
|
||||
queue.AppendElement(root);
|
||||
while (queue.Length()) {
|
||||
|
@ -296,6 +264,23 @@ CompositorParent::GetPrimaryScrollableLayer()
|
|||
}
|
||||
#endif
|
||||
|
||||
// Go down shadow layer tree, setting properties to match their non-shadow
|
||||
// counterparts.
|
||||
static void
|
||||
SetShadowProperties(Layer* aLayer)
|
||||
{
|
||||
// FIXME: Bug 717688 -- Do these updates in ShadowLayersParent::RecvUpdate.
|
||||
ShadowLayer* shadow = aLayer->AsShadowLayer();
|
||||
shadow->SetShadowTransform(aLayer->GetTransform());
|
||||
shadow->SetShadowVisibleRegion(aLayer->GetVisibleRegion());
|
||||
shadow->SetShadowClipRect(aLayer->GetClipRect());
|
||||
|
||||
for (Layer* child = aLayer->GetFirstChild();
|
||||
child; child = child->GetNextSibling()) {
|
||||
SetShadowProperties(child);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositorParent::TransformShadowTree()
|
||||
{
|
||||
|
|