Add Pale Moon

This commit is contained in:
NTD 2018-02-02 03:35:06 -05:00 committed by Roy Tam
commit fe8028fa2e
1173 changed files with 143053 additions and 934 deletions

View file

@ -0,0 +1,7 @@
Please see the file ../toolkit/content/license.html for the copyright
licensing conditions attached to this codebase, including copies of the
licenses concerned.
You are not granted rights or licenses to the trademarks of the
Mozilla Foundation, Moonchild Productions or any party, including without
limitation the Pale Moon name or logo.

View file

@ -0,0 +1,13 @@
# 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/.
include $(topsrcdir)/config/rules.mk
ifdef MAKENSISU
# For Windows build the uninstaller during the application build since the
# uninstaller is included with the application for mar file generation.
libs::
$(MAKE) -C installer/windows uninstaller
endif

View file

@ -0,0 +1 @@
PURGECACHES_DIRS = $(DIST)/bin/browser

View file

@ -0,0 +1,17 @@
# vim: set filetype=python:
# 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/.
if not CONFIG['LIBXUL_SDK']:
include('/toolkit/toolkit.mozbuild')
if CONFIG['MOZ_EXTENSIONS']:
DIRS += ['/extensions']
DIRS += ['/%s' % CONFIG['MOZ_BRANDING_DIRECTORY']]
# Never add tier dirs after browser because they apparently won't get
# packaged properly on Mac.
DIRS += ['/browser']

View file

@ -0,0 +1,116 @@
# 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/.
dist_dest = $(DIST)/$(MOZ_MACBUNDLE_NAME)
# hardcode en-US for the moment
AB_CD = en-US
DEFINES += \
-DAB_CD=$(AB_CD) \
-DAPP_VERSION="$(MOZ_APP_VERSION)" \
-DFIREFOX_ICO=\"$(DIST)/branding/firefox.ico\" \
-DDOCUMENT_ICO=\"$(DIST)/branding/document.ico\" \
-DNEWWINDOW_ICO=\"$(DIST)/branding/newwindow.ico\" \
-DNEWTAB_ICO=\"$(DIST)/branding/newtab.ico\" \
-DPBMODE_ICO=\"$(DIST)/branding/pbmode.ico\" \
$(NULL)
# Build a binary bootstrapping with XRE_main
ifndef MOZ_WINCONSOLE
ifdef MOZ_DEBUG
MOZ_WINCONSOLE = 1
else
MOZ_WINCONSOLE = 0
endif
endif
# This switches $(INSTALL) to copy mode, like $(SYSINSTALL), so things that
# shouldn't get 755 perms need $(IFLAGS1) for either way of calling nsinstall.
NSDISTMODE = copy
include $(topsrcdir)/config/config.mk
ifeq ($(OS_ARCH),WINNT)
# Rebuild firefox.exe if the manifest changes - it's included by splash.rc.
# (this dependency should really be just for firefox.exe, not other targets)
EXTRA_DEPS += $(PROGRAM).manifest
endif
PROGRAMS_DEST = $(DIST)/bin
include $(topsrcdir)/config/rules.mk
ifneq (,$(filter-out WINNT,$(OS_ARCH)))
ifdef COMPILE_ENVIRONMENT
libs::
cp -p $(MOZ_APP_NAME)$(BIN_SUFFIX) $(DIST)/bin/$(MOZ_APP_NAME)-bin$(BIN_SUFFIX)
endif
GARBAGE += $(addprefix $(FINAL_TARGET)/defaults/pref/, palemoon.js)
endif
ifdef MOZ_WIDGET_GTK
libs::
$(INSTALL) $(IFLAGS1) $(DIST)/branding/mozicon128.png $(FINAL_TARGET)/icons
$(INSTALL) $(IFLAGS1) $(DIST)/branding/default16.png $(FINAL_TARGET)/chrome/icons/default
$(INSTALL) $(IFLAGS1) $(DIST)/branding/default32.png $(FINAL_TARGET)/chrome/icons/default
$(INSTALL) $(IFLAGS1) $(DIST)/branding/default48.png $(FINAL_TARGET)/chrome/icons/default
endif
ifndef LIBXUL_SDK
# channel-prefs.js is handled separate from other prefs due to bug 756325
libs:: $(srcdir)/profile/channel-prefs.js
$(NSINSTALL) -D $(DIST)/bin/defaults/pref
$(call py_action,preprocessor,-Fsubstitution $(PREF_PPFLAGS) $(ACDEFINES) $^ -o $(DIST)/bin/defaults/pref/channel-prefs.js)
endif
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
MAC_APP_NAME = $(MOZ_APP_DISPLAYNAME)
ifdef MOZ_DEBUG
MAC_APP_NAME := $(MAC_APP_NAME)Debug
endif
AB_CD = $(MOZ_UI_LOCALE)
AB := $(firstword $(subst -, ,$(AB_CD)))
clean clobber repackage::
$(RM) -r $(dist_dest)
MAC_BUNDLE_VERSION = $(shell $(PYTHON) $(srcdir)/macversion.py --version=$(MOZ_APP_VERSION) --buildid=$(DEPTH)/config/buildid)
.PHONY: repackage
tools repackage:: $(PROGRAM)
$(MKDIR) -p $(dist_dest)/Contents/MacOS
$(MKDIR) -p $(dist_dest)/Contents/Resources/$(AB).lproj
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents $(dist_dest) --exclude English.lproj
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(dist_dest)/Contents/Resources/$(AB).lproj
sed -e 's/%APP_VERSION%/$(MOZ_APP_VERSION)/' -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' -e 's/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/' -e 's/%MAC_BUNDLE_VERSION%/$(MAC_BUNDLE_VERSION)/' $(srcdir)/macbuild/Contents/Info.plist.in > $(dist_dest)/Contents/Info.plist
sed -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(dist_dest)/Contents/Resources/$(AB).lproj/InfoPlist.strings
rsync -a --exclude-from='$(srcdir)/macbuild/Contents/MacOS-files.in' $(DIST)/bin/ $(dist_dest)/Contents/Resources
rsync -a --include-from='$(srcdir)/macbuild/Contents/MacOS-files.in' --exclude '*' $(DIST)/bin/ $(dist_dest)/Contents/MacOS
$(RM) $(dist_dest)/Contents/MacOS/$(PROGRAM)
rsync -aL $(PROGRAM) $(dist_dest)/Contents/MacOS
cp -RL $(DIST)/branding/firefox.icns $(dist_dest)/Contents/Resources/firefox.icns
cp -RL $(DIST)/branding/document.icns $(dist_dest)/Contents/Resources/document.icns
printf APPLMOZB > $(dist_dest)/Contents/PkgInfo
endif
ifdef LIBXUL_SDK #{
ifndef SKIP_COPY_XULRUNNER #{
libs::
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) #{
rsync -a --copy-unsafe-links $(LIBXUL_DIST)/XUL.framework $(dist_dest)/Contents/Frameworks
else
$(NSINSTALL) -D $(DIST)/bin/xulrunner
(cd $(LIBXUL_SDK)/bin && tar $(TAR_CREATE_FLAGS) - .) | (cd $(DIST)/bin/xulrunner && tar -xf -)
endif #} cocoa
endif #} SKIP_COPY_XULRUNNER
endif #} LIBXUL_SDK

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
_CodeSignature/CodeResources

View file

@ -0,0 +1,222 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>html</string>
<string>htm</string>
<string>shtml</string>
<string>xht</string>
<string>xhtml</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>HTML Document</string>
<key>CFBundleTypeOSTypes</key>
<array>
<string>HTML</string>
</array>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>svg</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>image/svg+xml</string>
</array>
<key>CFBundleTypeName</key>
<string>SVG document</string>
<key>CFBundleTypeOSTypes</key>
<array>
<string>TEXT</string>
</array>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>NSDocumentClass</key>
<string>BrowserDocument</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>text</string>
<string>txt</string>
<string>js</string>
<string>log</string>
<string>css</string>
<string>xul</string>
<string>rdf</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>Text Document</string>
<key>CFBundleTypeOSTypes</key>
<array>
<string>TEXT</string>
<string>utxt</string>
</array>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>jpeg</string>
<string>jpg</string>
<string>png</string>
<string>gif</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>fileBookmark.icns</string>
<key>CFBundleTypeName</key>
<string>document.icns</string>
<key>CFBundleTypeOSTypes</key>
<array>
<string>GIFf</string>
<string>JPEG</string>
<string>PNGf</string>
</array>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>oga</string>
<string>ogg</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>audio/ogg</string>
</array>
<key>CFBundleTypeName</key>
<string>HTML5 Audio (Ogg)</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>ogv</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>video/ogg</string>
</array>
<key>CFBundleTypeName</key>
<string>HTML5 Video (Ogg)</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>webm</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>video/webm</string>
</array>
<key>CFBundleTypeName</key>
<string>HTML5 Video (WebM)</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>palemoon</string>
<key>CFBundleGetInfoString</key>
<string>%MAC_APP_NAME% %APP_VERSION%</string>
<key>CFBundleIconFile</key>
<string>firefox</string>
<key>CFBundleIdentifier</key>
<string>%MOZ_MACBUNDLE_ID%</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>%MAC_APP_NAME%</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>%APP_VERSION%</string>
<key>CFBundleSignature</key>
<string>MOZB</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLIconFile</key>
<string>document.icns</string>
<key>CFBundleURLName</key>
<string>http URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>http</string>
</array>
</dict>
<dict>
<key>CFBundleURLIconFile</key>
<string>document.icns</string>
<key>CFBundleURLName</key>
<string>https URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>https</string>
</array>
</dict>
<dict>
<key>CFBundleURLName</key>
<string>ftp URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>ftp</string>
</array>
</dict>
<dict>
<key>CFBundleURLName</key>
<string>file URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>file</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>%MAC_BUNDLE_VERSION%</string>
<key>NSAppleScriptEnabled</key>
<true/>
<key>LSApplicationCategoryType</key>
<string>public.app-category.productivity</string>
<key>LSMinimumSystemVersion</key>
<string>10.6</string>
<key>LSMinimumSystemVersionByArchitecture</key>
<dict>
<key>i386</key>
<string>10.6.0</string>
<key>x86_64</key>
<string>10.6.0</string>
</dict>
<key>NSSupportsAutomaticGraphicsSwitching</key>
<true/>
<key>NSPrincipalClass</key>
<string>GoannaNSApplication</string>
</dict>
</plist>

View file

@ -0,0 +1,10 @@
/*.app/***
/*.dylib
/certutil
/firefox-bin
/gtest/***
/pk12util
/ssltunnel
/xpcshell
/XUL

View file

@ -0,0 +1,5 @@
/* 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/. */
CFBundleName = "%MAC_APP_NAME%";

View file

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>rules</key>
<dict>
<key>^Info.plist$</key>
<true/>
<key>^PkgInfo$</key>
<true/>
<key>^MacOS/</key>
<true/>
<key>^Resources/</key>
<true/>
<key>^MacOS/distribution/.*</key><dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^MacOS/override.ini</key><dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^MacOS/updates/.*</key><dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^MacOS/active-update.xml$</key><dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^MacOS/defaults/.*</key><dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^MacOS/removed-files$</key><dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^MacOS/updates.xml$</key><dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^Updated.app/.*</key><dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^updating/.*</key><dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
</dict>
</dict>
</plist>

View file

@ -0,0 +1,44 @@
#!/usr/bin/python
# 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/.
from optparse import OptionParser
import sys
import re
o = OptionParser()
o.add_option("--buildid", dest="buildid")
o.add_option("--version", dest="version")
(options, args) = o.parse_args()
if not options.buildid:
print >>sys.stderr, "--buildid is required"
sys.exit(1)
if not options.version:
print >>sys.stderr, "--version is required"
sys.exit(1)
# We want to build a version number that matches the format allowed for
# CFBundleVersion (nnnnn[.nn[.nn]]). We'll incorporate both the version
# number as well as the date, so that it changes at least daily (for nightly
# builds), but also so that newly-built older versions (e.g. beta build) aren't
# considered "newer" than previously-built newer versions (e.g. a trunk nightly)
buildid = open(options.buildid, 'r').read()
# extract only the major version (i.e. "14" from "14.0b1")
majorVersion = re.match(r'^(\d+)[^\d].*', options.version).group(1)
# last two digits of the year
twodigityear = buildid[2:4]
month = buildid[4:6]
if month[0] == '0':
month = month[1]
day = buildid[6:8]
if day[0] == '0':
day = day[1]
print '%s.%s.%s' % (majorVersion + twodigityear, month, day)

View file

@ -0,0 +1,8 @@
WIN32_MODULE_COMPANYNAME=Moonchild Productions
WIN32_MODULE_COPYRIGHT=©Pale Moon, Firefox and Mozilla Developers, available under the MPL 2.0.
WIN32_MODULE_PRODUCTVERSION=@MOZ_APP_WINVERSION@
WIN32_MODULE_PRODUCTVERSION_STRING=@MOZ_APP_VERSION@
WIN32_MODULE_TRADEMARKS=The Pale Moon logo and project names are the property of Moonchild Productions.
WIN32_MODULE_DESCRIPTION=Pale Moon web browser
WIN32_MODULE_PRODUCTNAME=Pale Moon
WIN32_MODULE_NAME=Pale Moon

View file

@ -0,0 +1,91 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DIRS += ['profile/extensions']
if CONFIG['OS_ARCH'] == 'WINNT' and CONFIG['MOZ_ASAN']:
GoannaProgram(CONFIG['MOZ_APP_NAME'])
else:
GoannaProgram(CONFIG['MOZ_APP_NAME'], msvcrt='static')
JS_PREFERENCE_FILES += [
'profile/palemoon.js',
]
if CONFIG['LIBXUL_SDK']:
PREF_JS_EXPORTS += [
'profile/channel-prefs.js',
]
SOURCES += [
'nsBrowserApp.cpp',
]
FINAL_TARGET_FILES += ['blocklist.xml']
FINAL_TARGET_FILES.defaults.profile += ['profile/prefs.js']
DEFINES['APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
for var in ('MOZILLA_OFFICIAL', 'LIBXUL_SDK'):
if CONFIG[var]:
DEFINES[var] = True
DEFINES['XPCOM_GLUE'] = True
GENERATED_INCLUDES += [
'/build',
]
LOCAL_INCLUDES += [
'/toolkit/xre',
'/xpcom/base',
'/xpcom/build',
]
DELAYLOAD_DLLS += [
'mozglue.dll',
]
USE_STATIC_LIBS = True
if CONFIG['_MSC_VER']:
# Always enter a Windows program through wmain, whether or not we're
# a console application.
WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup']
if CONFIG['OS_ARCH'] == 'WINNT':
RCINCLUDE = 'splash.rc'
DEFINES['MOZ_PHOENIX'] = True
# Control the default heap size.
# This is the heap returned by GetProcessHeap().
# As we use the CRT heap, the default size is too large and wastes VM.
#
# The default heap size is 1MB on Win32.
# The heap will grow if need be.
#
# Set it to 256k. See bug 127069.
if CONFIG['OS_ARCH'] == 'WINNT' and not CONFIG['GNU_CC']:
LDFLAGS += ['/HEAP:0x40000']
if CONFIG['OS_ARCH'] == 'WINNT':
USE_LIBS += [
'mozglue',
'xpcomglue_staticruntime',
]
else:
USE_LIBS += [
'xpcomglue',
]
DISABLE_STL_WRAPPING = True
if CONFIG['MOZ_LINKER']:
OS_LIBS += CONFIG['MOZ_ZLIB_LIBS']
if CONFIG['HAVE_CLOCK_MONOTONIC']:
OS_LIBS += CONFIG['REALTIME_LIBS']

View file

@ -0,0 +1,452 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "nsXULAppAPI.h"
#include "mozilla/AppData.h"
#include "application.ini.h"
#include "nsXPCOMGlue.h"
#if defined(XP_WIN)
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#include <windows.h>
#include <winbase.h>
#include <VersionHelpers.h>
#include <stdlib.h>
#include <io.h>
#include <fcntl.h>
#elif defined(XP_UNIX)
#include <sys/resource.h>
#include <time.h>
#include <unistd.h>
#endif
#ifdef XP_MACOSX
#include <mach/mach_time.h>
#include "MacQuirks.h"
#endif
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include "nsCOMPtr.h"
#include "nsIFile.h"
#include "nsStringGlue.h"
// Easy access to a five second startup delay used to get
// a debugger attached in the metro environment.
// #define DEBUG_delay_start_metro
#ifdef XP_WIN
// we want a wmain entry point
#include "nsWindowsWMain.cpp"
#define snprintf _snprintf
#define strcasecmp _stricmp
#endif
#include "BinaryPath.h"
#include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
#include "mozilla/StartupTimeline.h"
using namespace mozilla;
#ifdef XP_MACOSX
#define kOSXResourcesFolder "Resources"
#endif
#define kDesktopFolder "browser"
#define kMetroFolder "metro"
#define kMetroAppIniFilename "metroapp.ini"
#ifdef XP_WIN
#define kMetroTestFile "tests.ini"
const char* kMetroConsoleIdParam = "testconsoleid=";
#endif
static void Output(const char *fmt, ... )
{
va_list ap;
va_start(ap, fmt);
#ifndef XP_WIN
vfprintf(stderr, fmt, ap);
#else
char msg[2048];
vsnprintf_s(msg, _countof(msg), _TRUNCATE, fmt, ap);
wchar_t wide_msg[2048];
MultiByteToWideChar(CP_UTF8,
0,
msg,
-1,
wide_msg,
_countof(wide_msg));
#if MOZ_WINCONSOLE
fwprintf_s(stderr, wide_msg);
#else
MessageBoxW(nullptr,
wide_msg,
L"Pale Moon",
MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
#endif
#endif
va_end(ap);
}
/**
* Return true if |arg| matches the given argument name.
*/
static bool IsArg(const char* arg, const char* s)
{
if (*arg == '-')
{
if (*++arg == '-')
++arg;
return !strcasecmp(arg, s);
}
#if defined(XP_WIN)
if (*arg == '/')
return !strcasecmp(++arg, s);
#endif
return false;
}
#ifdef XP_WIN
/*
* AttachToTestHarness - Windows helper for when we are running
* in the immersive environment. Firefox is launched by Windows in
* response to a request by metrotestharness, which is launched by
* runtests.py. As such stdout in fx doesn't point to the right
* stream. This helper touches up stdout such that test output gets
* routed to a named pipe metrotestharness creates and dumps to its
* stdout.
*/
static void AttachToTestHarness()
{
// attach to the metrotestharness named logging pipe
HANDLE winOut = CreateFileA("\\\\.\\pipe\\metrotestharness",
GENERIC_WRITE,
FILE_SHARE_WRITE, 0,
OPEN_EXISTING, 0, 0);
if (winOut == INVALID_HANDLE_VALUE) {
OutputDebugStringW(L"Could not create named logging pipe.\n");
return;
}
// Set the c runtime handle
int stdOut = _open_osfhandle((intptr_t)winOut, _O_APPEND);
if (stdOut == -1) {
OutputDebugStringW(L"Could not open c-runtime handle.\n");
return;
}
FILE *fp = _fdopen(stdOut, "a");
*stdout = *fp;
}
#endif
XRE_GetFileFromPathType XRE_GetFileFromPath;
XRE_CreateAppDataType XRE_CreateAppData;
XRE_FreeAppDataType XRE_FreeAppData;
#ifdef XRE_HAS_DLL_BLOCKLIST
XRE_SetupDllBlocklistType XRE_SetupDllBlocklist;
#endif
XRE_StartupTimelineRecordType XRE_StartupTimelineRecord;
XRE_mainType XRE_main;
XRE_StopLateWriteChecksType XRE_StopLateWriteChecks;
static const nsDynamicFunctionLoad kXULFuncs[] = {
{ "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
{ "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
{ "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData },
#ifdef XRE_HAS_DLL_BLOCKLIST
{ "XRE_SetupDllBlocklist", (NSFuncPtr*) &XRE_SetupDllBlocklist },
#endif
{ "XRE_StartupTimelineRecord", (NSFuncPtr*) &XRE_StartupTimelineRecord },
{ "XRE_main", (NSFuncPtr*) &XRE_main },
{ "XRE_StopLateWriteChecks", (NSFuncPtr*) &XRE_StopLateWriteChecks },
{ nullptr, nullptr }
};
static int do_main(int argc, char* argv[], nsIFile *xreDirectory)
{
nsCOMPtr<nsIFile> appini;
nsresult rv;
uint32_t mainFlags = 0;
#ifdef XP_WIN
if (!IsWindowsVistaOrGreater()) {
Output("Couldn't load valid PE image.\n");
return 255;
}
#endif
// Allow palemoon.exe to launch XULRunner apps via -app <application.ini>
// Note that -app must be the *first* argument.
const char *appDataFile = getenv("XUL_APP_FILE");
if (appDataFile && *appDataFile) {
rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appini));
if (NS_FAILED(rv)) {
Output("Invalid path found: '%s'", appDataFile);
return 255;
}
}
else if (argc > 1 && IsArg(argv[1], "app")) {
if (argc == 2) {
Output("Incorrect number of arguments passed to -app");
return 255;
}
rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(appini));
if (NS_FAILED(rv)) {
Output("application.ini path not recognized: '%s'", argv[2]);
return 255;
}
char appEnv[MAXPATHLEN];
snprintf(appEnv, MAXPATHLEN, "XUL_APP_FILE=%s", argv[2]);
if (putenv(appEnv)) {
Output("Couldn't set %s.\n", appEnv);
return 255;
}
argv[2] = argv[0];
argv += 2;
argc -= 2;
}
if (appini) {
nsXREAppData *appData;
rv = XRE_CreateAppData(appini, &appData);
if (NS_FAILED(rv)) {
Output("Couldn't read application.ini");
return 255;
}
// xreDirectory already has a refcount from NS_NewLocalFile
appData->xreDirectory = xreDirectory;
int result = XRE_main(argc, argv, appData, mainFlags);
XRE_FreeAppData(appData);
return result;
}
// Desktop browser launch
ScopedAppData appData(&sAppData);
nsCOMPtr<nsIFile> exeFile;
rv = mozilla::BinaryPath::GetFile(argv[0], getter_AddRefs(exeFile));
if (NS_FAILED(rv)) {
Output("Couldn't find the application directory.\n");
return 255;
}
nsCOMPtr<nsIFile> greDir;
exeFile->GetParent(getter_AddRefs(greDir));
#ifdef XP_MACOSX
nsCOMPtr<nsIFile> parent;
greDir->GetParent(getter_AddRefs(parent));
greDir = parent.forget();
greDir->AppendNative(NS_LITERAL_CSTRING(kOSXResourcesFolder));
#endif
nsCOMPtr<nsIFile> appSubdir;
greDir->Clone(getter_AddRefs(appSubdir));
appSubdir->Append(NS_LITERAL_STRING(kDesktopFolder));
SetStrongPtr(appData.directory, static_cast<nsIFile*>(appSubdir.get()));
// xreDirectory already has a refcount from NS_NewLocalFile
appData.xreDirectory = xreDirectory;
return XRE_main(argc, argv, &appData, mainFlags);
}
/**
* Local TimeStamp::Now()-compatible implementation used to record timestamps
* which will be passed to XRE_StartupTimelineRecord().
*/
static uint64_t
TimeStamp_Now()
{
#ifdef XP_WIN
LARGE_INTEGER freq;
::QueryPerformanceFrequency(&freq);
return GetTickCount64() * freq.QuadPart;
#elif defined(XP_MACOSX)
return mach_absolute_time();
#elif defined(HAVE_CLOCK_MONOTONIC)
struct timespec ts;
int rv = clock_gettime(CLOCK_MONOTONIC, &ts);
if (rv != 0) {
return 0;
}
uint64_t baseNs = (uint64_t)ts.tv_sec * 1000000000;
return baseNs + (uint64_t)ts.tv_nsec;
#endif
}
static bool
FileExists(const char *path)
{
#ifdef XP_WIN
wchar_t wideDir[MAX_PATH];
MultiByteToWideChar(CP_UTF8, 0, path, -1, wideDir, MAX_PATH);
DWORD fileAttrs = GetFileAttributesW(wideDir);
return fileAttrs != INVALID_FILE_ATTRIBUTES;
#else
return access(path, R_OK) == 0;
#endif
}
#ifdef LIBXUL_SDK
# define XPCOM_PATH "xulrunner" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL
#else
# define XPCOM_PATH XPCOM_DLL
#endif
static nsresult
InitXPCOMGlue(const char *argv0, nsIFile **xreDirectory)
{
char exePath[MAXPATHLEN];
nsresult rv = mozilla::BinaryPath::Get(argv0, exePath);
if (NS_FAILED(rv)) {
Output("Couldn't find the application directory.\n");
return rv;
}
char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]);
if (!lastSlash || (size_t(lastSlash - exePath) > MAXPATHLEN - sizeof(XPCOM_PATH) - 1))
return NS_ERROR_FAILURE;
strcpy(lastSlash + 1, XPCOM_PATH);
lastSlash += sizeof(XPCOM_PATH) - sizeof(XPCOM_DLL);
if (!FileExists(exePath)) {
#if defined(LIBXUL_SDK) && defined(XP_MACOSX)
// Check for <bundle>/Contents/Frameworks/XUL.framework/libxpcom.dylib
bool greFound = false;
CFBundleRef appBundle = CFBundleGetMainBundle();
if (!appBundle)
return NS_ERROR_FAILURE;
CFURLRef fwurl = CFBundleCopyPrivateFrameworksURL(appBundle);
CFURLRef absfwurl = nullptr;
if (fwurl) {
absfwurl = CFURLCopyAbsoluteURL(fwurl);
CFRelease(fwurl);
}
if (absfwurl) {
CFURLRef xulurl =
CFURLCreateCopyAppendingPathComponent(nullptr, absfwurl,
CFSTR("XUL.framework"),
true);
if (xulurl) {
CFURLRef xpcomurl =
CFURLCreateCopyAppendingPathComponent(nullptr, xulurl,
CFSTR("libxpcom.dylib"),
false);
if (xpcomurl) {
if (CFURLGetFileSystemRepresentation(xpcomurl, true,
(UInt8*) exePath,
sizeof(exePath)) &&
access(tbuffer, R_OK | X_OK) == 0) {
if (realpath(tbuffer, exePath)) {
greFound = true;
}
}
CFRelease(xpcomurl);
}
CFRelease(xulurl);
}
CFRelease(absfwurl);
}
}
if (!greFound) {
#endif
Output("Could not find the Mozilla runtime.\n");
return NS_ERROR_FAILURE;
}
// We do this because of data in bug 771745
XPCOMGlueEnablePreload();
rv = XPCOMGlueStartup(exePath);
if (NS_FAILED(rv)) {
Output("Couldn't load XPCOM.\n");
return rv;
}
rv = XPCOMGlueLoadXULFunctions(kXULFuncs);
if (NS_FAILED(rv)) {
Output("Couldn't load XRE functions.\n");
return rv;
}
NS_LogInit();
// chop XPCOM_DLL off exePath
*lastSlash = '\0';
#ifdef XP_MACOSX
lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]);
strcpy(lastSlash + 1, kOSXResourcesFolder);
#endif
#ifdef XP_WIN
rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(exePath), false,
xreDirectory);
#else
rv = NS_NewNativeLocalFile(nsDependentCString(exePath), false,
xreDirectory);
#endif
return rv;
}
int main(int argc, char* argv[])
{
#ifdef DEBUG_delay_start_metro
Sleep(5000);
#endif
uint64_t start = TimeStamp_Now();
#ifdef XP_MACOSX
TriggerQuirks();
#endif
int gotCounters;
#if defined(XP_UNIX)
struct rusage initialRUsage;
gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage);
#elif defined(XP_WIN)
IO_COUNTERS ioCounters;
gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
#endif
nsIFile *xreDirectory;
nsresult rv = InitXPCOMGlue(argv[0], &xreDirectory);
if (NS_FAILED(rv)) {
return 255;
}
XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
#ifdef XRE_HAS_DLL_BLOCKLIST
XRE_SetupDllBlocklist();
#endif
int result = do_main(argc, argv, xreDirectory);
NS_LogTerm();
#ifdef XP_MACOSX
// Allow writes again. While we would like to catch writes from static
// destructors to allow early exits to use _exit, we know that there is
// at least one such write that we don't control (see bug 826029). For
// now we enable writes again and early exits will have to use exit instead
// of _exit.
XRE_StopLateWriteChecks();
#endif
return result;
}

View file

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="*"
name="Pale Moon"
type="win32"
/>
<description>Pale Moon</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
<ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
<ms_asmv3:security>
<ms_asmv3:requestedPrivileges>
<ms_asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false" />
</ms_asmv3:requestedPrivileges>
</ms_asmv3:security>
</ms_asmv3:trustInfo>
<ms_asmv3:application xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
<ms_asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</ms_asmv3:windowsSettings>
</ms_asmv3:application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
</application>
</compatibility>
</assembly>

View file

@ -0,0 +1,6 @@
#filter substitution
/* 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/. */
pref("app.update.channel", "@MOZ_UPDATE_CHANNEL@");

View file

@ -0,0 +1,7 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DIRS += ['{972ce4c6-7e08-4474-a285-3208198ce6fd}']

View file

@ -0,0 +1,10 @@
#
# 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/.
FILES := \
install.rdf.in \
$(NULL)
FILES_PATH = $(FINAL_TARGET)/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}
PP_TARGETS := FILES

View file

@ -0,0 +1,40 @@
<?xml version="1.0"?>
<!-- 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/. -->
#filter substitution
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>{972ce4c6-7e08-4474-a285-3208198ce6fd}</em:id>
<em:version>@MOZ_APP_VERSION@</em:version>
<!-- Target Application this theme can install into,
with minimum and maximum supported versions. -->
<em:targetApplication>
<Description>
<em:id>@MOZ_APP_ID@</em:id>
<em:minVersion>@MOZ_APP_VERSION@</em:minVersion>
<em:maxVersion>@MOZ_APP_VERSION@</em:maxVersion>
</Description>
</em:targetApplication>
<!-- Front End MetaData -->
<em:name>Default</em:name>
<em:description>The default theme.</em:description>
<!-- Front End Integration Hooks (used by Theme Manager)-->
<em:creator>Moonchild Productions</em:creator>
<em:contributor>Mozilla Contributors</em:contributor>
<!-- Allow lightweight themes to apply to this theme -->
<em:skinnable>true</em:skinnable>
<em:internalName>classic/1.0</em:internalName>
</Description>
</RDF>

View file

@ -0,0 +1,8 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
DEFINES['MOZ_APP_ID'] = CONFIG['MOZ_APP_ID']

View file

@ -0,0 +1,7 @@
<?xml version="1.0"?> <!-- -*- Mode: SGML -*- -->
<!-- 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/. -->
<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"/>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,13 @@
/* 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/. */
# Mozilla User Preferences
/* Do not edit this file.
*
* If you make changes to this file while the browser is running,
* the changes will be overwritten when the browser exits.
*
* To make a manual change to preferences, you can visit the URL about:config
*/

View file

@ -0,0 +1,21 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include <windows.h>
#include "nsNativeAppSupportWin.h"
1 24 "palemoon.exe.manifest"
IDI_APPICON ICON FIREFOX_ICO
IDI_DOCUMENT ICON DOCUMENT_ICO
IDI_APPLICATION ICON FIREFOX_ICO
IDI_NEWWINDOW ICON NEWWINDOW_ICO
IDI_NEWTAB ICON NEWTAB_ICO
IDI_PBMODE ICON PBMODE_ICO
STRINGTABLE DISCARDABLE
BEGIN
IDS_STARTMENU_APPNAME, "@MOZ_APP_DISPLAYNAME@"
END

View file

@ -0,0 +1,70 @@
/* 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/. */
#PMaboutDialog {
width: 620px;
}
#PMrightBox {
background-image: url("chrome://branding/content/about-wordmark.png");
background-repeat: no-repeat;
/* padding-top creates room for the wordmark */
padding-top: 38px;
margin-top:20px;
}
#PMrightBox:-moz-locale-dir(rtl) {
background-position: 100% 0;
}
#PMbottomBox {
padding: 15px 10px 0;
}
#PMversion {
margin-top: 10px;
-moz-margin-start: 0;
-moz-user-select: text;
-moz-user-focus: normal;
cursor: text;
}
#distribution,
#distributionId {
font-weight: bold;
display: none;
margin-top: 0;
margin-bottom: 0;
}
.text-blurb {
margin-bottom: 10px;
-moz-margin-start: 0;
-moz-padding-start: 0;
}
#updateButton,
#updateDeck > hbox > label {
-moz-margin-start: 0;
-moz-padding-start: 0;
}
.update-throbber {
width: 16px;
min-height: 16px;
-moz-margin-end: 3px;
list-style-image: url("chrome://global/skin/icons/loading_16.png");
}
.text-link,
.text-link:focus {
margin: 0px;
padding: 0px;
}
.bottom-link,
.bottom-link:focus {
text-align: center;
margin: 0 40px;
}

View file

@ -0,0 +1,590 @@
# 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/.
// Services = object with smart getters for common XPCOM services
Components.utils.import("resource://gre/modules/Services.jsm");
function init(aEvent)
{
if (aEvent.target != document)
return;
try {
var distroId = Services.prefs.getCharPref("distribution.id");
if (distroId) {
var distroVersion = Services.prefs.getCharPref("distribution.version");
var distroIdField = document.getElementById("distributionId");
distroIdField.value = distroId + " - " + distroVersion;
distroIdField.style.display = "block";
try {
// This is in its own try catch due to bug 895473 and bug 900925.
var distroAbout = Services.prefs.getComplexValue("distribution.about",
Components.interfaces.nsISupportsString);
var distroField = document.getElementById("distribution");
distroField.value = distroAbout;
distroField.style.display = "block";
}
catch (ex) {
// Pref is unset
Components.utils.reportError(ex);
}
}
}
catch (e) {
// Pref is unset
}
// Include the build ID if this is an "a#" or "b#" build
let version = Services.appinfo.version;
if (/[ab]\d+$/.test(version)) {
let buildID = Services.appinfo.appBuildID;
let buildDate = buildID.slice(0,4) + "-" + buildID.slice(4,6) + "-" + buildID.slice(6,8);
document.getElementById("PMversion").textContent += " (" + buildDate + ")";
}
#ifdef MOZ_UPDATER
gAppUpdater = new appUpdater();
#endif
#ifdef XP_MACOSX
// it may not be sized at this point, and we need its width to calculate its position
window.sizeToContent();
window.moveTo((screen.availWidth / 2) - (window.outerWidth / 2), screen.availHeight / 5);
#endif
// get release notes URL from prefs
var formatter = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
.getService(Components.interfaces.nsIURLFormatter);
var releaseNotesURL = formatter.formatURLPref("app.releaseNotesURL");
if (releaseNotesURL != "about:blank") {
var relnotes = document.getElementById("releaseNotesURL");
relnotes.setAttribute("href", releaseNotesURL);
}
}
#ifdef MOZ_UPDATER
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
Components.utils.import("resource://gre/modules/AddonManager.jsm");
var gAppUpdater;
function onUnload(aEvent) {
if (gAppUpdater.isChecking)
gAppUpdater.checker.stopChecking(Components.interfaces.nsIUpdateChecker.CURRENT_CHECK);
// Safe to call even when there isn't a download in progress.
gAppUpdater.removeDownloadListener();
gAppUpdater = null;
}
function appUpdater()
{
this.updateDeck = document.getElementById("updateDeck");
// Hide the update deck when there is already an update window open to avoid
// syncing issues between them.
if (Services.wm.getMostRecentWindow("Update:Wizard")) {
this.updateDeck.hidden = true;
return;
}
XPCOMUtils.defineLazyServiceGetter(this, "aus",
"@mozilla.org/updates/update-service;1",
"nsIApplicationUpdateService");
XPCOMUtils.defineLazyServiceGetter(this, "checker",
"@mozilla.org/updates/update-checker;1",
"nsIUpdateChecker");
XPCOMUtils.defineLazyServiceGetter(this, "um",
"@mozilla.org/updates/update-manager;1",
"nsIUpdateManager");
this.bundle = Services.strings.
createBundle("chrome://browser/locale/browser.properties");
this.updateBtn = document.getElementById("updateButton");
// The button label value must be set so its height is correct.
this.setupUpdateButton("update.checkInsideButton");
let manualURL = Services.urlFormatter.formatURLPref("app.update.url.manual");
let manualLink = document.getElementById("manualLink");
manualLink.value = manualURL;
manualLink.href = manualURL;
document.getElementById("failedLink").href = manualURL;
if (this.updateDisabledAndLocked) {
this.selectPanel("adminDisabled");
return;
}
if (this.isPending || this.isApplied) {
this.setupUpdateButton("update.restart." +
(this.isMajor ? "upgradeButton" : "updateButton"));
return;
}
if (this.aus.isOtherInstanceHandlingUpdates) {
this.selectPanel("otherInstanceHandlingUpdates");
return;
}
if (this.isDownloading) {
this.startDownload();
return;
}
if (this.updateEnabled && this.updateAuto) {
this.selectPanel("checkingForUpdates");
this.isChecking = true;
this.checker.checkForUpdates(this.updateCheckListener, true);
return;
}
}
appUpdater.prototype =
{
// true when there is an update check in progress.
isChecking: false,
// true when there is an update already staged / ready to be applied.
get isPending() {
if (this.update) {
return this.update.state == "pending" ||
this.update.state == "pending-service";
}
return this.um.activeUpdate &&
(this.um.activeUpdate.state == "pending" ||
this.um.activeUpdate.state == "pending-service");
},
// true when there is an update already installed in the background.
get isApplied() {
if (this.update)
return this.update.state == "applied" ||
this.update.state == "applied-service";
return this.um.activeUpdate &&
(this.um.activeUpdate.state == "applied" ||
this.um.activeUpdate.state == "applied-service");
},
// true when there is an update download in progress.
get isDownloading() {
if (this.update)
return this.update.state == "downloading";
return this.um.activeUpdate &&
this.um.activeUpdate.state == "downloading";
},
// true when the update type is major.
get isMajor() {
if (this.update)
return this.update.type == "major";
return this.um.activeUpdate.type == "major";
},
// true when updating is disabled by an administrator.
get updateDisabledAndLocked() {
return !this.updateEnabled &&
Services.prefs.prefIsLocked("app.update.enabled");
},
// true when updating is enabled.
get updateEnabled() {
try {
return Services.prefs.getBoolPref("app.update.enabled");
}
catch (e) { }
return true; // Firefox default is true
},
// true when updating in background is enabled.
get backgroundUpdateEnabled() {
return this.updateEnabled &&
gAppUpdater.aus.canStageUpdates;
},
// true when updating is automatic.
get updateAuto() {
try {
return Services.prefs.getBoolPref("app.update.auto");
}
catch (e) { }
return true; // Firefox default is true
},
/**
* Sets the deck's selected panel.
*
* @param aChildID
* The id of the deck's child to select.
*/
selectPanel: function(aChildID) {
this.updateDeck.selectedPanel = document.getElementById(aChildID);
this.updateBtn.disabled = (aChildID != "updateButtonBox");
},
/**
* Sets the update button's label and accesskey.
*
* @param aKeyPrefix
* The prefix for the properties file entry to use for setting the
* label and accesskey.
*/
setupUpdateButton: function(aKeyPrefix) {
this.updateBtn.label = this.bundle.GetStringFromName(aKeyPrefix + ".label");
this.updateBtn.accessKey = this.bundle.GetStringFromName(aKeyPrefix + ".accesskey");
if (!document.commandDispatcher.focusedElement ||
document.commandDispatcher.focusedElement == this.updateBtn)
this.updateBtn.focus();
},
/**
* Handles oncommand for the update button.
*/
buttonOnCommand: function() {
if (this.isPending || this.isApplied) {
// Notify all windows that an application quit has been requested.
let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"].
createInstance(Components.interfaces.nsISupportsPRBool);
Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
// Something aborted the quit process.
if (cancelQuit.data)
return;
let appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"].
getService(Components.interfaces.nsIAppStartup);
// If already in safe mode restart in safe mode (bug 327119)
if (Services.appinfo.inSafeMode) {
appStartup.restartInSafeMode(Components.interfaces.nsIAppStartup.eAttemptQuit);
return;
}
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit |
Components.interfaces.nsIAppStartup.eRestart);
return;
}
const URI_UPDATE_PROMPT_DIALOG = "chrome://mozapps/content/update/updates.xul";
// Firefox no longer displays a license for updates and the licenseURL check
// is just in case a distibution does.
if (this.update) {
var ary = null;
ary = Components.classes["@mozilla.org/supports-array;1"].
createInstance(Components.interfaces.nsISupportsArray);
ary.AppendElement(this.update);
var openFeatures = "chrome,centerscreen,dialog=no,resizable=no,titlebar,toolbar=no";
Services.ww.openWindow(null, URI_UPDATE_PROMPT_DIALOG, "", openFeatures, ary);
window.close();
return;
}
this.selectPanel("checkingForUpdates");
this.isChecking = true;
this.checker.checkForUpdates(this.updateCheckListener, true);
},
/**
* Implements nsIUpdateCheckListener. The methods implemented by
* nsIUpdateCheckListener are in a different scope from nsIIncrementalDownload
* to make it clear which are used by each interface.
*/
updateCheckListener: {
/**
* See nsIUpdateService.idl
*/
onCheckComplete: function(aRequest, aUpdates, aUpdateCount) {
gAppUpdater.isChecking = false;
gAppUpdater.update = gAppUpdater.aus.
selectUpdate(aUpdates, aUpdates.length);
if (!gAppUpdater.update) {
gAppUpdater.selectPanel("noUpdatesFound");
return;
}
if (gAppUpdater.update.unsupported) {
if (gAppUpdater.update.detailsURL) {
let unsupportedLink = document.getElementById("unsupportedLink");
unsupportedLink.href = gAppUpdater.update.detailsURL;
}
gAppUpdater.selectPanel("unsupportedSystem");
return;
}
if (!gAppUpdater.aus.canApplyUpdates) {
gAppUpdater.selectPanel("manualUpdate");
return;
}
gAppUpdater.selectPanel("updateButtonBox");
gAppUpdater.setupUpdateButton("update.openUpdateUI." +
(this.isMajor ? "upgradeButton"
: "applyButton"));
},
/**
* See nsIUpdateService.idl
*/
onError: function(aRequest, aUpdate) {
// Errors in the update check are treated as no updates found. If the
// update check fails repeatedly without a success the user will be
// notified with the normal app update user interface so this is safe.
gAppUpdater.isChecking = false;
gAppUpdater.selectPanel("noUpdatesFound");
},
/**
* See nsISupports.idl
*/
QueryInterface: function(aIID) {
if (!aIID.equals(Components.interfaces.nsIUpdateCheckListener) &&
!aIID.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
},
/**
* Checks the compatibility of add-ons for the application update.
*/
checkAddonCompatibility: function() {
var self = this;
AddonManager.getAllAddons(function(aAddons) {
self.addons = [];
self.addonsCheckedCount = 0;
aAddons.forEach(function(aAddon) {
// Protect against code that overrides the add-ons manager and doesn't
// implement the isCompatibleWith or the findUpdates method.
if (!("isCompatibleWith" in aAddon) || !("findUpdates" in aAddon)) {
let errMsg = "Add-on doesn't implement either the isCompatibleWith " +
"or the findUpdates method!";
if (aAddon.id)
errMsg += " Add-on ID: " + aAddon.id;
Components.utils.reportError(errMsg);
return;
}
// If an add-on isn't appDisabled and isn't userDisabled then it is
// either active now or the user expects it to be active after the
// restart. If that is the case and the add-on is not installed by the
// application and is not compatible with the new application version
// then the user should be warned that the add-on will become
// incompatible. If an addon's type equals plugin it is skipped since
// checking plugins compatibility information isn't supported and
// getting the scope property of a plugin breaks in some environments
// (see bug 566787).
try {
if (aAddon.type != "plugin" && aAddon.isCompatible &&
!aAddon.appDisabled && !aAddon.userDisabled &&
aAddon.scope != AddonManager.SCOPE_APPLICATION &&
!aAddon.isCompatibleWith(self.update.appVersion,
self.update.platformVersion))
self.addons.push(aAddon);
}
catch (e) {
Components.utils.reportError(e);
}
});
self.addonsTotalCount = self.addons.length;
if (self.addonsTotalCount == 0) {
self.startDownload();
return;
}
self.checkAddonsForUpdates();
});
},
/**
* Checks if there are updates for add-ons that are incompatible with the
* application update.
*/
checkAddonsForUpdates: function() {
this.addons.forEach(function(aAddon) {
aAddon.findUpdates(this, AddonManager.UPDATE_WHEN_NEW_APP_DETECTED,
this.update.appVersion,
this.update.platformVersion);
}, this);
},
/**
* See XPIProvider.jsm
*/
onCompatibilityUpdateAvailable: function(aAddon) {
for (var i = 0; i < this.addons.length; ++i) {
if (this.addons[i].id == aAddon.id) {
this.addons.splice(i, 1);
break;
}
}
},
/**
* See XPIProvider.jsm
*/
onUpdateAvailable: function(aAddon, aInstall) {
if (!Services.blocklist.isAddonBlocklisted(aAddon.id, aInstall.version,
this.update.appVersion,
this.update.platformVersion)) {
// Compatibility or new version updates mean the same thing here.
this.onCompatibilityUpdateAvailable(aAddon);
}
},
/**
* See XPIProvider.jsm
*/
onUpdateFinished: function(aAddon) {
++this.addonsCheckedCount;
if (this.addonsCheckedCount < this.addonsTotalCount)
return;
if (this.addons.length == 0) {
// Compatibility updates or new version updates were found for all add-ons
this.startDownload();
return;
}
this.selectPanel("updateButtonBox");
this.setupUpdateButton("update.openUpdateUI." +
(this.isMajor ? "upgradeButton" : "applyButton"));
},
/**
* Starts the download of an update mar.
*/
startDownload: function() {
if (!this.update)
this.update = this.um.activeUpdate;
this.update.QueryInterface(Components.interfaces.nsIWritablePropertyBag);
this.update.setProperty("foregroundDownload", "true");
this.aus.pauseDownload();
let state = this.aus.downloadUpdate(this.update, false);
if (state == "failed") {
this.selectPanel("downloadFailed");
return;
}
this.setupDownloadingUI();
},
/**
* Switches to the UI responsible for tracking the download.
*/
setupDownloadingUI: function() {
this.downloadStatus = document.getElementById("downloadStatus");
this.downloadStatus.value =
DownloadUtils.getTransferTotal(0, this.update.selectedPatch.size);
this.selectPanel("downloading");
this.aus.addDownloadListener(this);
},
removeDownloadListener: function() {
if (this.aus) {
this.aus.removeDownloadListener(this);
}
},
/**
* See nsIRequestObserver.idl
*/
onStartRequest: function(aRequest, aContext) {
},
/**
* See nsIRequestObserver.idl
*/
onStopRequest: function(aRequest, aContext, aStatusCode) {
switch (aStatusCode) {
case Components.results.NS_ERROR_UNEXPECTED:
if (this.update.selectedPatch.state == "download-failed" &&
(this.update.isCompleteUpdate || this.update.patchCount != 2)) {
// Verification error of complete patch, informational text is held in
// the update object.
this.removeDownloadListener();
this.selectPanel("downloadFailed");
break;
}
// Verification failed for a partial patch, complete patch is now
// downloading so return early and do NOT remove the download listener!
break;
case Components.results.NS_BINDING_ABORTED:
// Do not remove UI listener since the user may resume downloading again.
break;
case Components.results.NS_OK:
this.removeDownloadListener();
if (this.backgroundUpdateEnabled) {
this.selectPanel("applying");
let update = this.um.activeUpdate;
let self = this;
Services.obs.addObserver(function (aSubject, aTopic, aData) {
// Update the UI when the background updater is finished
let status = aData;
if (status == "applied" || status == "applied-service" ||
status == "pending" || status == "pending-service") {
// If the update is successfully applied, or if the updater has
// fallen back to non-staged updates, show the Restart to Update
// button.
self.selectPanel("updateButtonBox");
self.setupUpdateButton("update.restart." +
(self.isMajor ? "upgradeButton" : "updateButton"));
} else if (status == "failed") {
// Background update has failed, let's show the UI responsible for
// prompting the user to update manually.
self.selectPanel("downloadFailed");
} else if (status == "downloading") {
// We've fallen back to downloading the full update because the
// partial update failed to get staged in the background.
// Therefore we need to keep our observer.
self.setupDownloadingUI();
return;
}
Services.obs.removeObserver(arguments.callee, "update-staged");
}, "update-staged", false);
} else {
this.selectPanel("updateButtonBox");
this.setupUpdateButton("update.restart." +
(this.isMajor ? "upgradeButton" : "updateButton"));
}
break;
default:
this.removeDownloadListener();
this.selectPanel("downloadFailed");
break;
}
},
/**
* See nsIProgressEventSink.idl
*/
onStatus: function(aRequest, aContext, aStatus, aStatusArg) {
},
/**
* See nsIProgressEventSink.idl
*/
onProgress: function(aRequest, aContext, aProgress, aProgressMax) {
this.downloadStatus.value =
DownloadUtils.getTransferTotal(aProgress, aProgressMax);
},
/**
* See nsISupports.idl
*/
QueryInterface: function(aIID) {
if (!aIID.equals(Components.interfaces.nsIProgressEventSink) &&
!aIID.equals(Components.interfaces.nsIRequestObserver) &&
!aIID.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
#endif

View file

@ -0,0 +1,120 @@
<?xml version="1.0"?> <!-- -*- Mode: HTML -*- -->
# 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://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/aboutDialog.css" type="text/css"?>
<?xml-stylesheet href="chrome://branding/content/aboutDialog.css" type="text/css"?>
<!DOCTYPE window [
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
%brandDTD;
<!ENTITY % aboutDialogDTD SYSTEM "chrome://browser/locale/aboutDialog.dtd" >
%aboutDialogDTD;
]>
#ifdef XP_MACOSX
<?xul-overlay href="chrome://browser/content/macBrowserOverlay.xul"?>
#endif
<window xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="PMaboutDialog"
windowtype="Browser:About"
onload="init(event);"
#ifdef MOZ_UPDATER
onunload="onUnload(event);"
#endif
#ifdef XP_MACOSX
inwindowmenu="false"
#else
title="&aboutDialog.title;"
#endif
role="dialog"
aria-describedby="version distribution distributionId communityDesc contributeDesc trademark"
>
<script type="application/javascript" src="chrome://browser/content/aboutDialog.js"/>
<vbox id="aboutPMDialogContainer">
<hbox id="PMclientBox">
<vbox id="PMleftBox" flex="1"/>
<vbox id="PMrightBox" flex="1">
#ifdef HAVE_64BIT_BUILD
#expand <label id="PMversion">Version: __MOZ_APP_VERSION__ (64-bit)</label>
#else
#expand <label id="PMversion">Version: __MOZ_APP_VERSION__ (32-bit)</label>
#endif
<label id="distribution" class="text-blurb"/>
<label id="distributionId" class="text-blurb"/>
<vbox id="detailsBox">
<vbox id="updateBox">
#ifdef MOZ_UPDATER
<deck id="updateDeck" orient="vertical">
<hbox id="updateButtonBox" align="center">
<button id="updateButton" align="start"
oncommand="gAppUpdater.buttonOnCommand();"/>
<spacer flex="1"/>
</hbox>
<hbox id="checkingForUpdates" align="center">
<image class="update-throbber"/><label>&update.checkingForUpdates;</label>
</hbox>
<hbox id="checkingAddonCompat" align="center">
<image class="update-throbber"/><label>&update.checkingAddonCompat;</label>
</hbox>
<hbox id="downloading" align="center">
<image class="update-throbber"/><label>&update.downloading.start;</label><label id="downloadStatus"/><label>&update.downloading.end;</label>
</hbox>
<hbox id="applying" align="center">
<image class="update-throbber"/><label>&update.applying;</label>
</hbox>
<hbox id="downloadFailed" align="center">
<label>&update.failed.start;</label><label id="failedLink" class="text-link">&update.failed.linkText;</label><label>&update.failed.end;</label>
</hbox>
<hbox id="adminDisabled" align="center">
<label>&update.adminDisabled;</label>
</hbox>
<hbox id="noUpdatesFound" align="center">
<label>&update.noUpdatesFound;</label>
</hbox>
<hbox id="manualUpdate" align="center">
<label>&update.manual.start;</label><label id="manualLink" class="text-link"/><label>&update.manual.end;</label>
</hbox>
</deck>
#endif
</vbox>
<description class="text-pmcreds">
Pale Moon is released by <label class="text-link" href="http://www.moonchildproductions.info">Moonchild Productions</label>.
</description>
<description class="text-pmcreds">
Special thanks to all our supporters and donors for making this browser possible!
</description>
<description class="text-blurb">
If you wish to contribute, please consider helping out by providing support to other users on the <label class="text-link" href="https://forum.palemoon.org/">Pale Moon forum</label>
or getting involved in our development by tackling some of the issues found in our GitHub issue tracker.
</description>
</vbox>
</vbox>
</hbox>
<vbox id="PMbottomBox">
<hbox pack="center">
<label class="text-link bottom-link" href="about:license">Licensing information</label>
<label class="text-link bottom-link" href="about:rights">End-user rights</label>
<label class="text-link bottom-link" id="releaseNotesURL">Release notes</label>
</hbox>
<description id="PMtrademark">&trademarkInfo.part1;</description>
</vbox>
</vbox>
<keyset>
<key keycode="VK_ESCAPE" oncommand="window.close();"/>
</keyset>
#ifdef XP_MACOSX
#include browserMountPoints.inc
#endif
</window>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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 html [
<!ENTITY % htmlDTD
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"DTD/xhtml1-strict.dtd">
%htmlDTD;
<!ENTITY % netErrorDTD
SYSTEM "chrome://global/locale/netError.dtd">
%netErrorDTD;
<!ENTITY % globalDTD
SYSTEM "chrome://global/locale/global.dtd">
%globalDTD;
<!ENTITY % aboutrobotsDTD
SYSTEM "chrome://browser/locale/aboutRobots.dtd">
%aboutrobotsDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>&robots.pagetitle;</title>
<link rel="stylesheet" href="chrome://global/skin/netError.css" type="text/css" media="all" />
<link rel="icon" type="image/png" id="favicon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAACGFjVEwAAAASAAAAAJNtBPIAAAAaZmNUTAAAAAAAAAAQAAAAEAAAAAAAAAAALuAD6AABhIDeugAAALhJREFUOI2Nk8sNxCAMRDlGohauXFOMpfTiAlxICqAELltHLqlgctg1InzMRhpFAc%2BLGWTnmoeZYamt78zXdZmaQtQMADlnU0OIAlbmJUBEcO4bRKQY2rUXIPmAGnDuG%2FBx3%2FfvOPVaDUg%2BoAPUf1PArIMCSD5glMEsUGaG%2BkyAFWIBaCsKuA%2BHGCNijLgP133XgOEtaPFMy2vUolEGJoCIzBmoRUR9%2B7rxj16DZaW%2FmgtmxnJ8V3oAnApQwNS5zpcAAAAaZmNUTAAAAAEAAAAQAAAAEAAAAAAAAAAAAB4D6AIB52fclgAAACpmZEFUAAAAAjiNY2AYBVhBc3Pzf2LEcGreqcbwH1kDNjHauWAUjAJyAADymxf9WF%2Bu8QAAABpmY1RMAAAAAwAAABAAAAAQAAAAAAAAAAAAHgPoAgEK8Q9%2FAAAAFmZkQVQAAAAEOI1jYBgFo2AUjAIIAAAEEAAB0xIn4wAAABpmY1RMAAAABQAAABAAAAAQAAAAAAAAAAAAHgPoAgHnO30FAAAAQGZkQVQAAAAGOI1jYBieYKcaw39ixHCC%2F6cwFWMTw2rz%2F1MM%2F6Vu%2Ff%2F%2F%2FxTD%2F51qEIwuRjsXILuEGLFRMApgAADhNCsVfozYcAAAABpmY1RMAAAABwAAABAAAAAQAAAAAAAAAAAAHgPoAgEKra7sAAAAFmZkQVQAAAAIOI1jYBgFo2AUjAIIAAAEEAABM9s3hAAAABpmY1RMAAAACQAAABAAAAAQAAAAAAAAAAAAHgPoAgHn3p%2BwAAAAKmZkQVQAAAAKOI1jYBgFWEFzc%2FN%2FYsRwat6pxvAfWQM2Mdq5YBSMAnIAAPKbF%2F1BhPl6AAAAGmZjVEwAAAALAAAAEAAAABAAAAAAAAAAAAAeA%2BgCAQpITFkAAAAWZmRBVAAAAAw4jWNgGAWjYBSMAggAAAQQAAHaszpmAAAAGmZjVEwAAAANAAAAEAAAABAAAAAAAAAAAAAeA%2BgCAeeCPiMAAABAZmRBVAAAAA44jWNgGJ5gpxrDf2LEcIL%2FpzAVYxPDavP%2FUwz%2FpW79%2F%2F%2F%2FFMP%2FnWoQjC5GOxcgu4QYsVEwCmAAAOE0KxUmBL0KAAAAGmZjVEwAAAAPAAAAEAAAABAAAAAAAAAAAAAeA%2BgCAQoU7coAAAAWZmRBVAAAABA4jWNgGAWjYBSMAggAAAQQAAEpOBELAAAAGmZjVEwAAAARAAAAEAAAABAAAAAAAAAAAAAeA%2BgCAeYVWtoAAAAqZmRBVAAAABI4jWNgGAVYQXNz839ixHBq3qnG8B9ZAzYx2rlgFIwCcgAA8psX%2FWvpAecAAAAaZmNUTAAAABMAAAAQAAAAEAAAAAAAAAAAAB4D6AIBC4OJMwAAABZmZEFUAAAAFDiNY2AYBaNgFIwCCAAABBAAAcBQHOkAAAAaZmNUTAAAABUAAAAQAAAAEAAAAAAAAAAAAB4D6AIB5kn7SQAAAEBmZEFUAAAAFjiNY2AYnmCnGsN%2FYsRwgv%2BnMBVjE8Nq8%2F9TDP%2Blbv3%2F%2F%2F8Uw%2F%2BdahCMLkY7FyC7hBixUTAKYAAA4TQrFc%2BcEoQAAAAaZmNUTAAAABcAAAAQAAAAEAAAAAAAAAAAAB4D6AIBC98ooAAAABZmZEFUAAAAGDiNY2AYBaNgFIwCCAAABBAAASCZDI4AAAAaZmNUTAAAABkAAAAQAAAAEAAAAAAAAAAAAB4D6AIB5qwZ%2FAAAACpmZEFUAAAAGjiNY2AYBVhBc3Pzf2LEcGreqcbwH1kDNjHauWAUjAJyAADymxf9cjJWbAAAABpmY1RMAAAAGwAAABAAAAAQAAAAAAAAAAAAHgPoAgELOsoVAAAAFmZkQVQAAAAcOI1jYBgFo2AUjAIIAAAEEAAByfEBbAAAABpmY1RMAAAAHQAAABAAAAAQAAAAAAAAAAAAHgPoAgHm8LhvAAAAQGZkQVQAAAAeOI1jYBieYKcaw39ixHCC%2F6cwFWMTw2rz%2F1MM%2F6Vu%2Ff%2F%2F%2FxTD%2F51qEIwuRjsXILuEGLFRMApgAADhNCsVlxR3%2FgAAABpmY1RMAAAAHwAAABAAAAAQAAAAAAAAAAAAHgPoAgELZmuGAAAAFmZkQVQAAAAgOI1jYBgFo2AUjAIIAAAEEAABHP5cFQAAABpmY1RMAAAAIQAAABAAAAAQAAAAAAAAAAAAHgPoAgHlgtAOAAAAKmZkQVQAAAAiOI1jYBgFWEFzc%2FN%2FYsRwat6pxvAfWQM2Mdq5YBSMAnIAAPKbF%2F0%2FMvDdAAAAAElFTkSuQmCC"/>
<script type="application/javascript"><![CDATA[
var buttonClicked = false;
function robotButton()
{
var button = document.getElementById('errorTryAgain');
if (buttonClicked) {
button.style.visibility = "hidden";
} else {
var newLabel = button.getAttribute("label2");
button.textContent = newLabel;
buttonClicked = true;
}
}
]]></script>
<style type="text/css"><![CDATA[
#errorPageContainer {
background-image: none;
}
#errorPageContainer:before {
content: url('chrome://browser/content/aboutRobots-icon.png');
position: absolute;
}
body[dir=rtl] #icon,
body[dir=rtl] #errorPageContainer:before {
transform: scaleX(-1);
}
]]></style>
</head>
<body dir="&locale.dir;">
<!-- PAGE CONTAINER (for styling purposes only) -->
<div id="errorPageContainer">
<!-- Error Title -->
<div id="errorTitle">
<h1 id="errorTitleText">&robots.errorTitleText;</h1>
</div>
<!-- LONG CONTENT (the section most likely to require scrolling) -->
<div id="errorLongContent">
<!-- Short Description -->
<div id="errorShortDesc">
<p id="errorShortDescText">&robots.errorShortDescText;</p>
</div>
<!-- Long Description (Note: See netError.dtd for used XHTML tags) -->
<div id="errorLongDesc">
<ul>
<li>&robots.errorLongDesc1;</li>
<li>&robots.errorLongDesc2;</li>
<li>&robots.errorLongDesc3;</li>
<li>&robots.errorLongDesc4;</li>
</ul>
</div>
<!-- Short Description -->
<div id="errorTrailerDesc">
<p id="errorTrailerDescText">&robots.errorTrailerDescText;</p>
</div>
</div>
<!-- Button -->
<button id="errorTryAgain"
label2="&robots.dontpress;"
onclick="robotButton();">&retry.label;</button>
<img src="chrome://browser/content/aboutRobots-widget-left.png"
style="position: absolute; bottom: -12px; left: -10px;"/>
<img src="chrome://browser/content/aboutRobots-widget-left.png"
style="position: absolute; bottom: -12px; right: -10px; transform: scaleX(-1);"/>
</div>
</body>
</html>

View file

@ -0,0 +1,339 @@
%if 0
/* 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/. */
%endif
html {
font: message-box;
font-size: 100%;
background-color: hsl(0,0%,90%);
color: #000;
height: 100%;
}
body {
margin: 0;
display: -moz-box;
-moz-box-orient: vertical;
width: 100%;
height: 100%;
background-image: url(chrome://browser/content/abouthome/noise.png),
linear-gradient(hsla(0,0%,100%,.7), hsla(0,0%,100%,.4));
}
input,
button {
font-size: inherit;
font-family: inherit;
}
a {
color: -moz-nativehyperlinktext;
text-decoration: none;
}
.spacer {
-moz-box-flex: 1;
}
#topSection {
text-align: center;
}
#brandLogo {
height: 192px;
width: 192px;
margin: 22px auto 31px;
background-image: url("chrome://branding/content/about-logo.png");
background-size: 192px auto;
background-position: center center;
background-repeat: no-repeat;
}
#searchForm {
width: 470px;
}
#searchForm {
display: -moz-box;
}
#searchLogoContainer {
display: -moz-box;
-moz-box-align: center;
padding-top: 2px;
-moz-padding-end: 8px;
}
#searchLogoContainer[hidden] {
display: none;
}
#searchEngineLogo {
display: inline-block;
height: 28px;
width: 70px;
min-width: 70px;
}
#searchText {
-moz-box-flex: 1;
padding: 6px 8px;
background: hsla(0,0%,100%,.9) padding-box;
border: 1px solid;
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
box-shadow: 0 1px 0 hsla(210,65%,9%,.02) inset,
0 0 2px hsla(210,65%,9%,.1) inset,
0 1px 0 hsla(0,0%,100%,.2);
border-radius: 2.5px 0 0 2.5px;
}
#searchText:-moz-dir(rtl) {
border-radius: 0 2.5px 2.5px 0;
}
#searchText:focus,
#searchText[autofocus] {
border-color: hsla(206,100%,60%,.6) hsla(206,76%,52%,.6) hsla(204,100%,40%,.6);
}
#searchSubmit {
-moz-margin-start: -1px;
background: linear-gradient(hsla(0,0%,100%,.8), hsla(0,0%,100%,.1)) padding-box;
padding: 0 9px;
border: 1px solid;
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
-moz-border-start: 1px solid transparent;
border-radius: 0 2.5px 2.5px 0;
box-shadow: 0 0 2px hsla(0,0%,100%,.5) inset,
0 1px 0 hsla(0,0%,100%,.2);
cursor: pointer;
transition-property: background-color, border-color, box-shadow;
transition-duration: 150ms;
}
#searchSubmit:-moz-dir(rtl) {
border-radius: 2.5px 0 0 2.5px;
}
#searchText:focus + #searchSubmit,
#searchText + #searchSubmit:hover,
#searchText[autofocus] + #searchSubmit {
border-color: #59b5fc #45a3e7 #3294d5;
color: white;
}
#searchText:focus + #searchSubmit,
#searchText[autofocus] + #searchSubmit {
background-image: linear-gradient(#4cb1ff, #1793e5);
box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset,
0 0 0 1px hsla(0,0%,100%,.1) inset,
0 1px 0 hsla(210,54%,20%,.03);
}
#searchText + #searchSubmit:hover {
background-image: linear-gradient(#66bdff, #0d9eff);
box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset,
0 0 0 1px hsla(0,0%,100%,.1) inset,
0 1px 0 hsla(210,54%,20%,.03),
0 0 4px hsla(206,100%,20%,.2);
}
#searchText + #searchSubmit:hover:active {
box-shadow: 0 1px 1px hsla(211,79%,6%,.1) inset,
0 0 1px hsla(211,79%,6%,.2) inset;
transition-duration: 0ms;
}
#launcher {
display: -moz-box;
-moz-box-align: center;
-moz-box-pack: center;
width: 100%;
background-color: hsla(0,0%,0%,.03);
border-top: 1px solid hsla(0,0%,0%,.03);
box-shadow: 0 1px 2px hsla(0,0%,0%,.02) inset,
0 -1px 0 hsla(0,0%,100%,.25);
}
#launcher:not([session]),
body[narrow] #launcher[session] {
display: block; /* display separator and restore button on separate lines */
text-align: center;
white-space: nowrap; /* prevent navigational buttons from wrapping */
}
.launchButton {
display: -moz-box;
-moz-box-orient: vertical;
margin: 16px 1px;
padding: 14px 6px;
min-width: 88px;
max-width: 176px;
max-height: 85px;
vertical-align: top;
white-space: normal;
background: transparent padding-box;
border: 1px solid transparent;
border-radius: 2.5px;
color: #525c66;
font-size: 75%;
cursor: pointer;
transition-property: background-color, border-color, box-shadow;
transition-duration: 150ms;
}
body[narrow] #launcher[session] > .launchButton {
margin: 4px 1px;
}
.launchButton:hover {
background-color: hsla(211,79%,6%,.03);
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
}
.launchButton:hover:active {
background-image: linear-gradient(hsla(211,79%,6%,.02), hsla(211,79%,6%,.05));
border-color: hsla(210,54%,20%,.2) hsla(210,54%,20%,.23) hsla(210,54%,20%,.25);
box-shadow: 0 1px 1px hsla(211,79%,6%,.05) inset,
0 0 1px hsla(211,79%,6%,.1) inset;
transition-duration: 0ms;
}
.launchButton[hidden],
#launcher:not([session]) > #restorePreviousSessionSeparator,
#launcher:not([session]) > #restorePreviousSession {
display: none;
}
#restorePreviousSessionSeparator {
width: 3px;
height: 116px;
margin: 0 10px;
background-image: linear-gradient(hsla(0,0%,100%,0), hsla(0,0%,100%,.35), hsla(0,0%,100%,0)),
linear-gradient(hsla(211,79%,6%,0), hsla(211,79%,6%,.2), hsla(211,79%,6%,0)),
linear-gradient(hsla(0,0%,100%,0), hsla(0,0%,100%,.35), hsla(0,0%,100%,0));
background-position: left top, center, right bottom;
background-size: 1px auto;
background-repeat: no-repeat;
}
body[narrow] #restorePreviousSessionSeparator {
margin: 0 auto;
width: 512px;
height: 3px;
background-image: linear-gradient(to right, hsla(0,0%,100%,0), hsla(0,0%,100%,.35), hsla(0,0%,100%,0)),
linear-gradient(to right, hsla(211,79%,6%,0), hsla(211,79%,6%,.2), hsla(211,79%,6%,0)),
linear-gradient(to right, hsla(0,0%,100%,0), hsla(0,0%,100%,.35), hsla(0,0%,100%,0));
background-size: auto 1px;
}
#restorePreviousSession {
max-width: none;
font-size: 90%;
}
body[narrow] #restorePreviousSession {
font-size: 80%;
}
.launchButton::before {
display: block;
width: 32px;
height: 32px;
margin: 0 auto 6px;
line-height: 0; /* remove extra vertical space due to non-zero font-size */
}
#downloads::before {
content: url("chrome://browser/content/abouthome/downloads.png");
}
#bookmarks::before {
content: url("chrome://browser/content/abouthome/bookmarks.png");
}
#history::before {
content: url("chrome://browser/content/abouthome/history.png");
}
#addons::before {
content: url("chrome://browser/content/abouthome/addons.png");
}
#sync::before {
content: url("chrome://browser/content/abouthome/sync.png");
}
#settings::before {
content: url("chrome://browser/content/abouthome/settings.png");
}
#restorePreviousSession::before {
content: url("chrome://browser/content/abouthome/restore-large.png");
height: 48px;
width: 48px;
display: inline-block; /* display on same line as text label */
vertical-align: middle;
margin-bottom: 0;
-moz-margin-end: 8px;
}
#restorePreviousSession:-moz-dir(rtl)::before {
transform: scaleX(-1);
}
body[narrow] #restorePreviousSession::before {
content: url("chrome://browser/content/abouthome/restore.png");
height: 32px;
width: 32px;
}
/* [HiDPI]
* At resolutions above 1dppx, prefer downscaling the 2x Retina graphics
* rather than upscaling the original-size ones (bug 818940).
*/
@media not all and (max-resolution: 1dppx) {
#brandLogo {
background-image: url("chrome://branding/content/about-logo@2x.png");
}
.launchButton::before {
transform: scale(.5);
transform-origin: 0 0;
}
#downloads::before {
content: url("chrome://browser/content/abouthome/downloads@2x.png");
}
#bookmarks::before {
content: url("chrome://browser/content/abouthome/bookmarks@2x.png");
}
#history::before {
content: url("chrome://browser/content/abouthome/history@2x.png");
}
#addons::before {
content: url("chrome://browser/content/abouthome/addons@2x.png");
}
#sync::before {
content: url("chrome://browser/content/abouthome/sync@2x.png");
}
#settings::before {
content: url("chrome://browser/content/abouthome/settings@2x.png");
}
#restorePreviousSession::before {
content: url("chrome://browser/content/abouthome/restore-large@2x.png");
}
body[narrow] #restorePreviousSession::before {
content: url("chrome://browser/content/abouthome/restore@2x.png");
}
}

View file

@ -0,0 +1,354 @@
/* 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/. */
const SEARCH_ENGINES = {
"Google": {
// This is the "2x" image designed for OS X retina resolution, Windows at 192dpi, etc.;
// it will be scaled down as necessary on lower-dpi displays.
image: "data:image/png;base64," +
"iVBORw0KGgoAAAANSUhEUgAAAIwAAAA4CAYAAAAvmxBdAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ" +
"bWFnZVJlYWR5ccllPAAAGrFJREFUeNrtfHt4VdW172+utZOASLJ5+BaIFrUeXkFsa0Fl++gDnznV" +
"VlvFxt7aqvUUarXtse3Bau35ak/rZ9XT26NtfOvV6wFET+FYCQEKWqsQIT5RCAgSXnlnrzXneNw/" +
"1lphJSSQ8BB7bub3zW+LO3uN+fiNMcf4jTEX0N/6W3/rb/2tv30smtnXB3zmRi2FQakxQNKX3WkW" +
"9S/tgW3HLpmQM543A0BWVSHMYGIwOTDxzxrOf3/RQQfMZ2/SLAvKhTFVBGUqKFONH2QAzwOMF38a" +
"wHhYZAxWAqhe/iszp3+b970d/sInc57vz/J8L2eMB2MAEYkBQ6DQ3dRw4dq7AUjcP3rAfPZmLWXC" +
"LHKoIAcQAUxaB5EaEfc6AEBhjDEwmcx43/fO9HxT4vkReBIAAZgjgodW3NcPnn1sHgD/iHknn+0d" +
"6s8XEUhsXXac/34WAAGw8afuT8GZ3X055YeSJcIsG+pMZwFn0UihezRofPt3G54f/0E8cNMN+Myo" +
"8jVTCgYd823PLzrPeIBnABiUQ1F+UoWsVOYb33mkoKp/7/dKyT0AGc47X4s0sjBEoLxbBqAQAMfW" +
"Rfe38B4BM+VHUkYOs8mi1FrABbK4dcvK73zwp1M3xYPOxANKBqbpCdXNGb0UwPKRF74xpfDQ0t+K" +
"54+IvlKoahmAhaO/mv/ZmicG3tqPgT61ZM2dZMQJOYhIdByRM/F3dCCOox4Bc3oEliqyyNoQCPPu" +
"sXceKZqRsigu7pwaWBowiRb46+f9Q1V2wl1nDx09/R7jF30x9adNlN8yPx4DHwht+B/cBIBoRqeI" +
"E4hE/oshTcB0wNbT6/o/zrhFyohR5ZxmrVWE+fDxdx4puhGAH4OkPe5B6pykeJAc/7cDEMZ/095Y" +
"870P339m+BXs2v4kbCFsm9u2vnpJ3bzR7wAo2B/R2v+PjSnyXcRxtOLUSXFxwAFz5i2SZUIVO82S" +
"BWye/vLOIwNvjL8OYqCEfXCmJAZPHkC7sK1REbj2+lmbq86qTVmmfuuyN2cTiREWKCvACgml9kDL" +
"7HQksehsZmSdA6yVpsa6P38v3swg7m4vN1dGXrThKGP8yS5fP33j/LEvxKDbl2f2A0YFCtkZQDOa" +
"PjLAnP4jrmBGjh1AVhG2ttxfX33++vjY2eeNXf/siLUAzgEwMJZrY2vF/Vu/t4BRqCqgCmj07wMV" +
"HXUCzJQfUlZE72ICnANcqNj21h8eiK1AX46gXh29KT9H+rd9XxBjYGCgig7QHOgjPgMAKigXQZYp" +
"si4uCOc3v35zY2wF9ufGSgxA7fdd9g8ho9ol4P4ojiQWnSUMMANECrJNy1NWYH8eGfsEvJbLv1IK" +
"1XIAUwEtA0xplJMwjcaYlTDeShg8dOgjj6/cJxNYfWIWkHJoh5yyjkSZ8RbB89YBZq4/pXafGeuz" +
"b9WciXJxo2B2houqgAjABJCLOwFMqFv57+bBxMIAJm1det3avnl1OYCLAeSgWhofaY1QXQSRuYc+" +
"/OiD3QLmUzNdqTBKhRVMADsF5beuToXJB90KtFz+lVIVniXOVUAUqjpXVB4WwPjGTPB8/0zjeTnj" +
"ezl43szmKy6vNkDF4MeeXNc3oJyUhfAMkJsJkSxUVrLos6o6z/O8Ucb3phrPzyHKeVTwkpPXseg3" +
"Cqe+1SfG+swfaw6KGTAoJ5eyGF3IBeEIJB2AcXxb0FI/L45uFQBMGiu6Z3ai9eqrclBUClFWVatV" +
"5GERNT5wEVQnQLUcIuVNX75kFjn60rA5c1d0AoywlkcxfdwZ2LSgbOmBZAv70povu7RcyFUqcZYd" +
"Pbxix44fnLv8pbYUOWh+P3ZM9uJRo34xoLDgq8b3YTxvqhqsaPzyJTdmn36msjdyqPqkMhWqBFGZ" +
"MtV8uDX4zMjp2zemyEoPgGn4zyOvGzy48A54GcD3Sz1jFrqqE+4uOOvdmb0ASlYEs5mQE9afUdhy" +
"0yv3lHzwya/8ZcjgI0+5yssU3QKYkgQ4Ivp60LL1n8kBQfOWuvdnj6uLldgHQKoKxU7HV/eg2y1X" +
"XXmXEs1U0ZVb29o//4k5c5P5eQB+s+68aVeUFBTcCxUoS6kRWfjhueecc9SfX3ytA9QTr7eVACqY" +
"FDYEwnbB2qcHHg6gLY6ODhpomi77coUyVaojhKH9+ZHzF/wqXiztEg34APxNX/jCvQOLCi83fpy8" +
"UsCJXHLYnGdn785S0uKTyyBUBXJZcW5x4bSN56ciyLQcD4Bf/+ThVwwbUvRb+JkoswqAWX5b9Lm1" +
"M3uSM/UnUiaCKiZk2blvvnxX0ePxuBNAmpMur51wyLBPzjVeBBoVwIXBk6vuP+SG+LkcuwkWAA96" +
"/JjZKnKxkACkkFb5Nztz220xX9bJlWi+6opKFalQlpqlmzZNu6B6SaJ0knKJ/DW5qd8p8TO3x6AB" +
"qza1EE06cdmy9wDAY5LjmBTMkQnUnZ42H0ywNF52aU6FK4UY5NySI+cv+E3MCnMM5HyqtwFoO3rB" +
"gmuDMFjGjiCOIEQwzH9c+7lzju+JTaYlJ2ehUqXMWWFqeurFxqsAFMVf25Ss9kTOEZdvebClJbxT" +
"yUGZoEzwlL/b9tzRX+pOztSfSBZApSqyIrL45buKnkaUJEzLCN5+csxr+ab6fyILkI2OIZYBlx9/" +
"2bYvpLgw2+EqKLKdwoceVKJp+tfuEpYKZcaW1tZbLqheEsbj3GV+oxdV3x0GwQZrHUIiWKIST3Vm" +
"DG54zFrKrBBWiGgSyx9Uv6Xh0n/MKlGlOII4h80trQ+kuJt8HGklZHg6FZF/Y/uOb7O1YOvAzkGt" +
"Kxmoehe6SYNEpkErwZIFC4I2fuLKf2tLtDOPzumPhA6wAPJDLt1yuzjaAEcAMUCMApXfvPP7IcO6" +
"gkYFs4RRpgy49qanUsAPu/T8W48e/YwL6S/kYtBYwM8U/yu6KVlQUShr9CkKyK7b1vDVy0qVeaYy" +
"gaxbdeK85/8a/z7sYR3zgXM1gXUInEPoCEw8PR6z8YQxaidQPh6RrgrPEOZS4chKjFuydEEKFD1x" +
"QgrAnfO3V98Jw/B5dhFgmByU+MK/nnrq6K6gcQtPyqlIubJAibCxPv/fsVVNgCI9yGEAQdBq71NH" +
"UEdQIoBo5PBBeklazuQfSpYFM0UAFsDmd2yMf9+1XkUT3otc8AiRwpFChCBCI0detGbSLtYr5uw6" +
"tk26XctZwgxhRt65ZSmr1t389M1Jk85wzKcHRAiJkCfasDnI/0sMGN+jlLMrAigMhp0+f+TBBIw4" +
"milEYOcQBHZZAoZeEIgKgIIgeJbD2MqEFhxaDAFmdAWMisxQFigzlAUnX9e4rA9yeHuTna3koBQB" +
"RogxwOPvxNbQAAA7VHQEFKSQKEFIu4lA5d3HiiuFNB4XQZlhUHBK11QO0oRdD7ouROVCkeJZG7ak" +
"/KBOYHlz4sTy1WVlVY5oYego2+bs82+3tFw6YcVrp01dteqpxNfyhKQuGlxCMSsKBh570ABT/8XP" +
"5dhRVpyDWAd2Ns0O9yrhWdfcMpvCEByEoNCCwhBgvgBdM+PM5TH5FPW+1ZLo8de2viehe12dhVoH" +
"OAtDPO61O4o+kYCTnE5wVuGsxlzKHul7BUDKdomKgwpB2QHAyNiP2Dl+0Z2WRXZ9YP0F55WJczvX" +
"0jp09U3fLiurWD1+/NqQaHZIVNbu3O1vt7aM+fSqVRWXvPvu0pRldwAkQ5brjO+NMh0kgMIvGjYZ" +
"wIKETPxIrYt1U5M8iThKJil9yZGc++ab298dP36Jb8wZohqhQHRErKEeAA6fG5FT5yIlYYI6tzfO" +
"vtiQni3MYDw0ChqEgUMyejyAdwGwDeW4ZI9FAGQOmwzgv/cERmZbDXhnKBNUGMJkUhGVduSSJJ1P" +
"6rw8HIalJo7ilBkchgCgL48fVzLceDc4kZnWUdap1AQi10x+660n4jXyk1M7ZXEZgHhMUkMO4Njp" +
"hQGMf8h56Fx++ZE1a+1xZC2Szjs3sk9uUEhUbSMvP3LeyOGZ0tKJiearo1J1DHVRPYmS7JUcG2g1" +
"pxxUsooBnpmQWAOb10YbKGygcKFCZOC0XqxrRKokCBQG5euX77In2k1P+2hhWEZBAAoCuCCEcW7E" +
"2xMn/m6oYo0jyjnmuc3Off6UN96YMvmtt5LILSmQ61r3xAA0I+xqPBiIejAd1f7e2MPPfvm4LQs/" +
"89a+bP6nZuSzfsaU+T7g+UBixYQVRFGS01kFO22srRy0EgA4CEvFRHS3MANMY/fGbybmlQqAFSBV" +
"sCp8kWwCGA5dqefFShnnRV77ecHYU37iXuqLoB0tsuIo34v3NfJR1GlJsrnOuiXGy1y8k+rwxh57" +
"3srSD/6rbLdra7yMqgjUCGAULR8uWr0LJPYAGApCeCbKNygLPKIxJ65YOSU+YpLUUCYGiqBzQVy3" +
"Ft1zbevnJl60UARqACgcVDo9ZZr63Mqua68QxlpmrWJC1FmrmLSKCFVktcpZrbKhzg4D26E5Lgjg" +
"8vnoMwwh1hU/dvTRo/qcDyJqcESw5Dp6o3XNHVrqLDSubAdFjuXwwWZcX+Wc9APboKxQUoiLurXa" +
"IYfCpjlCDsoxZ6OCouLRt+xpbY3nA8aDMR6E2+9vffOWxl02cQ+Bbdjevt7l83D5ABRaKNHYO484" +
"YmgMkoJ4jElCOL8Lz9NN87YumrRDxc2DElQZKgIVhZcZcO1hZ74wtK/H0thvtuXGXdM2S0S/ziQ1" +
"FPJiG7pHwvbgDhtKnQ0VNhCEeUHQLmiuf2fymieGvJGY8DCfX+yCEC5xWIlwtO+P6+s4VESJGS4+" +
"liwxKjZ/2FGRZvPhYgktxEZdHWOAr2P34ihWIQWTgJ2CnWJbo9Ymz1g/5+h1QsF9wgKJ19Z4hV87" +
"4fKNE3cnx8v4V8H4UOjqhvce+zW6qdWVlOvSjQsDlw/WUT4A5QNQGIJDizMPHXR+CiRBb4GSzlYr" +
"26Z7vYKSC42nUOPBqA9VU1I0ZOJPEYWj1NvVW/3AoEUAFgO4IzZ1hYk2jf9WUw7IjCIXHUVhXrFp" +
"/sQtKZPIoXXr/PjoSkZeoHo6gP/bFyeciECqcHG3IrXp37a2SF3xQNPxRAXgq5nS1bHsDWCYALYA" +
"u+h0W/impI8Pad9ec/vAoWVTjV84Nsn5FAwcvmDMN5rOqf1jyatdHzjuGjvThloKYH3b5qVXt775" +
"44ZuN1QEKknF3a6ImfDee4tWjBrV6R5Qoeq1AP6Avaxx8gDolhdPXAh2qzQmZFQ4ZhALrj/mvLpT" +
"+qhxya0BP5VVZQBkA6jNR0AJ2xUUcjKGjsx4k3PVYUwaJU6rJ3reLiHlHppjBjF3fLYSzU/noEZ8" +
"3611VusoVJBVsFWAdezim/3jemSFe+SNIsvCpAhCXf7TBZI+PnTr4nO2t2xcME3ZroYKIouEEqDo" +
"xfHfav/GxOttFgBOucGWll0XVqrqXYDWNLz3aG7bsovWp4i2TvkhScLqNBezq/M/zxLBxV2Yx/75" +
"yCPP6usc04CJ+B3bcLMwQTiK+0UIwgz1ip8+4pyaYX0x0SnWMkjnYGygkm9nBO0MGzoI2TTDyQBw" +
"7ubNawPmeZYZNt5wZhrxX8OHX9yXSTJzGcVgIWasbs8/hc7XRzXM670cg0Vs5H+MHm6u74ucrb/K" +
"lAlFPoySoqFFn+rm+OCGV762df2cYWe4fP0M5qDWhoowRIm1/h+s1YZx3wrVOV1LDhXMaGzfXntF" +
"46vXtMQRS/clsqRRT9SNd0GMBo6edRStZbKeg4D//ciQIcP2CTDbqsdVKQePq1JMFkXxv4qO9AaM" +
"fPGoaeuG9kXp0LkU0wGgMFC1gYAdAeyg0m3IrE3W3mtTvodjRpHq9X3xL4h5Qsq63P/z9ra6LqSc" +
"vvmBPkwOTex2lnf4wNee/47fa99NGGVJ8Zl1qP3UPfwkdr15mDDV+Y3Pf+Kh9c9kz9pee89J7dve" +
"vaRt+7qLbVv47y5UUKggp3BB/okNz0/aHI8332OaIgELxWDpptQtt6X+Qcu03nVYGQYxjxzl+7/e" +
"GyvjdYrCtv31JiW7QTjy6qWj83jF4AeP/MLaodiHRtZBXAihEEIWkq4eSgGmvKGhqpX5d1YEVhiW" +
"BaI6Zf6QITN7s5ELhw4tZZavkwhIZMOC1rZfo5s64nPv4+1NzXot2/hYiqKckglH4/7eRojCOosp" +
"St6u2ijfS1Hv3I0SdVy5aam9ecumBeOqN8w7aRkxSlMVdRDmRHa4m5xWPKPEusUA6maIrcy/cCKw" +
"InASKaCoXrlo2LAH+xpMpAEjLauu2ObaNnxVmZqUHaI8SaR+KnIhTPHCo6ZtOn6vk4qUPNNGnV2P" +
"J0ptENweMq92zHBMcMwwIrfMLS6etKdJEnMlCYOZm9YE4dUPkWvsIUckJ/+SZwd5PCEOEBc5rh7j" +
"grqf+VfvSc7mO/xZSihVAra3YMY/PqqrUhZVe7C8yRHTBqAVQJuQN5idgJ2ASQAz4PJjptWevKc0" +
"RZQ0TQATRWDd/dmFDQ2VeaLH0z4dRVTK9EXZ7IqFJSXH7W6eLw0blntp2NAydGOSqPGVs/5mW9Zc" +
"JGKbRSxELIRDCFuIuAmiBa8eMW37rcdc1JDtM+3PYdSp43k9/ulPgmDrsnz+vFBktRWBZYEVKSlU" +
"feH5wYPP7u5Hfy4uzi4oLq50IjkSaXrf2vIfBPnV6PlKiwKg0XfyNe2BPkmJ8+oUGeh/bLjNu7En" +
"0Gy+w5sppLcyKRra9IZJ98hTvciop9MPSSFUwGTnEjHICsgpyKHYHzjquWMvrJ+wewUENPFjCIAx" +
"k3uStyIMbw5FVieWJvJpBE5kgqq+X1VcPGdRcfHMxSUluSUlJbmlUZ+1tKRkLRGVnrZ9Rw12rSLt" +
"sDpFg8vmfbpw0HH3wcuMMSaiao2XAbwMjPFhPL/ReN6DfsY8tHHekN0WXR929vqsCpWruFshPEqF" +
"o3IyADuWTxgea1rYTbRVeEMmc+SnCwp+OcB4l3kmLq0D4BnzkA/MMUBjvDMXC1DBqlkCFr9N9E//" +
"HIZpPyDsQVuTFwsMfP273k8GFeLbvo9izwe8DGA8VMPgIc/D2piALlPFDGWUMqNuazOun/RbeQU7" +
"L/zl0cfC+SPOXjG84NBRawCvJNoSE7PiBgr5Xx/MKf7jLnzIbUPKlHVF5C11KgJfD9+shY8Vxjd3" +
"0780rEvP8bFDDvnVQGO+lU5MeTDwzM5aTbOzNyrw/XNbWx9JFLknk+sjqjobUHJq9XS/cNj3jZcZ" +
"Ac9PwBIDyAeMD2O8RhhvpTFYqYpGqMQOM2UhlFOhsvjfgNJ6ofxyoZaXbHPt8mDNjDU9ACYBbyGA" +
"AT/KZEZ/MpO5qciYyRlgROeJGSh0nQCL21Ufmx4EL8dMpqScRt4DFVAAYMCtORx+0Rhz7aFF+GJB" +
"BmNM/JKklGo1KlBtHZ474U79P9hZOZcQYb0unD/mwu05qADCZwE4C8Y7I3kTk4kFx+mUuzfMKf5e" +
"+rn+rUMq4PR4hFII0gw0xpdvGAWGoDqHf9m8IuV8m2Qtf1pQMPok37+50JhpHlC8EzwRcAzwOqs+" +
"Vkv06I+da04nInd3RvuxgCIAhcUTF5zvFQ79oucP+Cy8zIjE6qQnt5Pviu5IqAogVKNCNSrBUte6" +
"blnrqi/Vo3O9rI3Pc7cbP6sgGQcAf7rvl3zK908uBKjAGK5jrrmNKKHj/RS3E6L3V2USLUzkZAB4" +
"i75pTivwwQMyoKYQ685+QOtScvzUHPbIlJ54ZVsuDPTrZDmnQqUQggo1qkoNRDyFeJ6XGQfjF0fW" +
"3O9YWxW6adNzw36Dzm/JKEJ0k7QgtfiSygd1vSrkdZ3jlb6fneT7Y+MN1xrmVX9gbkw9q1MdsemF" +
"U5wkpwqSRSw49gfZAcPPHOsVlIww/sBjjPEVnqfGZEQlWKVCjWK31TW/dv56pCruU126TGxPl+US" +
"IrAgNQ7TQ+pNukQqfalLNimApvMt6CZMTvsiu3VOJ17XnrNWZ9m85oK8Qmz4sFB+CeXrF29dfOqG" +
"1PwKs6fOKyvKjrnb8wrHGD8TWfCOEoX85zb96dgXY9leN2NM+y3SJZG4u7XsSldIykFPz09NHxbR" +
"T2U3M11AsKf8aRqtnBqQoG91oWkGOS0/XaQo2Pf3u5mUDK9LukD7Mv5Tv9teSQ4VzipsINUtW9Zc" +
"t/mFiRu7WbcOuQNP+MXQ4hGX3mEKBl1mjB9bbwAqSz6cf+TZ8Qaabta/u6hM92ItpZs5dvyor5R/" +
"dwvp9QAa6eFzfxRlpVMk2mXh93czeyPn1Bn5ShWtYAJsyEve+OPgC7Hzmgx3USDtejQedlbtDX7h" +
"0Ns6HChV5LcvP7rpb1+qx/690dHrtewL05c2c7ZLtrM91fOpDGjXyvT9+WYBPQAg3NPcey1n4vVt" +
"FUJSIfGNjJZNy2ekkqzpazIJOefSoTaA9q1VY+5Wbvs9NAoYVBkFh5Sesi9lJ/u6lt5+WETpoi2M" +
"PpZU/k9szmKGtVGRWBjQ6g3zP78pxfSGKb+tJ4LPAsi31S/+uXCUlVZmCIc+DlI15L4Cpr/1FA1d" +
"0VLqAilzgcCGChdQc5eoTXqpkNS66hv1YLsUElURiG1sOZj7lunf3v3fwlBKjRfX9EjEHKcscV98" +
"D40zRKIqgEpz4yvTVnfjU/VbmL/r4yhwTTbPCNsZNi8g50/OnvbCsXu5wQqVURCBuOb7seu98n7A" +
"/L23Tc8NX8mW6pL73UoOhYPH/GJv/I7Dzlqbg5pRUG1q++A//+Ng+4f9gDlATVzLHfErZiHioKrn" +
"H37uhgeG597sdYnIYeeszypQqQawre9dHNbd0Yj9/5KnfsB8DJpuXXj8Q+ryj3dUZglD1Uz3MsWv" +
"HX7uh1fv6QGHn7upAmrWQpEV2zSt+bVptamw+6C9VaP/hcoHrvkABgydUjPLywy6Oboh6HW6PgLj" +
"LYqStqYRQHKDMQflMhXOQrnata27tvGvufrEn8ZBfmdPP2AO7NpmAAw85B8qTyjKlt1svAHTjPGL" +
"k4w0jAcTAyllnBoh9Kxw/tEdS8cuT0WyH4vX1PYD5qMBzQDE2eFDxz09zsscWuwVHX6a8YwaFAiM" +
"NAkHr4vdUdf82rQN6JwnSl4N4vAxeKdxP2A+mjXuKTvcXcY9TdOnyxPk4zKZ/vbRAqe75C3QfZZY" +
"0P/y6/7299z+H4QrdGsoib8JAAAAAElFTkSuQmCC"
},
"DuckDuckGo": {
image: "data:image/png;base64," +
"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"
}
};
// This global tracks if the page has been set up before, to prevent double inits
let gInitialized = false;
let gObserver = new MutationObserver(function (mutations) {
for (let mutation of mutations) {
if (mutation.attributeName == "searchEngineURL") {
setupSearchEngine();
if (!gInitialized) {
gInitialized = true;
}
return;
}
}
});
window.addEventListener("pageshow", function () {
// Delay search engine setup, cause browser.js::BrowserOnAboutPageLoad runs
// later and may use asynchronous getters.
window.gObserver.observe(document.documentElement, { attributes: true });
fitToWidth();
window.addEventListener("resize", fitToWidth);
});
window.addEventListener("pagehide", function() {
window.gObserver.disconnect();
window.removeEventListener("resize", fitToWidth);
});
function onSearchSubmit(aEvent)
{
let searchTerms = document.getElementById("searchText").value;
let searchURL = document.documentElement.getAttribute("searchEngineURL");
if (searchURL && searchTerms.length > 0) {
// Send an event that a search was performed. This was originally
// added so Firefox Health Report could record that a search from
// about:home had occurred.
let engineName = document.documentElement.getAttribute("searchEngineName");
let event = new CustomEvent("AboutHomeSearchEvent", {detail: engineName});
document.dispatchEvent(event);
const SEARCH_TOKEN = "_searchTerms_";
let searchPostData = document.documentElement.getAttribute("searchEnginePostData");
if (searchPostData) {
// Check if a post form already exists. If so, remove it.
const POST_FORM_NAME = "searchFormPost";
let form = document.forms[POST_FORM_NAME];
if (form) {
form.parentNode.removeChild(form);
}
// Create a new post form.
form = document.body.appendChild(document.createElement("form"));
form.setAttribute("name", POST_FORM_NAME);
// Set the URL to submit the form to.
form.setAttribute("action", searchURL.replace(SEARCH_TOKEN, searchTerms));
form.setAttribute("method", "post");
// Create new <input type=hidden> elements for search param.
searchPostData = searchPostData.split("&");
for (let postVar of searchPostData) {
let [name, value] = postVar.split("=");
if (value == SEARCH_TOKEN) {
value = searchTerms;
}
let input = document.createElement("input");
input.setAttribute("type", "hidden");
input.setAttribute("name", name);
input.setAttribute("value", value);
form.appendChild(input);
}
// Submit the form.
form.submit();
} else {
searchURL = searchURL.replace(SEARCH_TOKEN, encodeURIComponent(searchTerms));
window.location.href = searchURL;
}
}
aEvent.preventDefault();
}
function setupSearchEngine()
{
// The "autofocus" attribute doesn't focus the form element
// immediately when the element is first drawn, so the
// attribute is also used for styling when the page first loads.
let searchText = document.getElementById("searchText");
searchText.addEventListener("blur", function searchText_onBlur() {
searchText.removeEventListener("blur", searchText_onBlur);
searchText.removeAttribute("autofocus");
});
let searchEngineName = document.documentElement.getAttribute("searchEngineName");
let searchEngineInfo = SEARCH_ENGINES[searchEngineName];
let logoElt = document.getElementById("searchEngineLogo");
// Add search engine logo.
if (searchEngineInfo && searchEngineInfo.image) {
logoElt.parentNode.hidden = false;
logoElt.src = searchEngineInfo.image;
logoElt.alt = searchEngineName;
searchText.placeholder = "";
}
else {
logoElt.parentNode.hidden = true;
searchText.placeholder = searchEngineName;
}
}
function fitToWidth() {
if (window.scrollMaxX) {
document.body.setAttribute("narrow", "true");
} else if (document.body.hasAttribute("narrow")) {
document.body.removeAttribute("narrow");
fitToWidth();
}
}

View file

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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 html [
<!ENTITY % htmlDTD
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"DTD/xhtml1-strict.dtd">
%htmlDTD;
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
%globalDTD;
<!ENTITY % aboutHomeDTD SYSTEM "chrome://browser/locale/aboutHome.dtd">
%aboutHomeDTD;
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd" >
%browserDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>&abouthome.pageTitle;</title>
<link rel="icon" type="image/png" id="favicon"
href="chrome://branding/content/icon32.png"/>
<link rel="stylesheet" type="text/css" media="all"
href="chrome://browser/content/abouthome/aboutHome.css"/>
<script type="text/javascript;version=1.8"
src="chrome://browser/content/abouthome/aboutHome.js"/>
</head>
<body dir="&locale.dir;">
<div class="spacer"/>
<div id="topSection">
<div id="brandLogo"></div>
<div id="searchContainer">
<form name="searchForm" id="searchForm" onsubmit="onSearchSubmit(event)">
<div id="searchLogoContainer"><img id="searchEngineLogo"/></div>
<input type="text" name="q" value="" id="searchText" maxlength="256"
autofocus="autofocus"/>
<input id="searchSubmit" type="submit" value="&abouthome.searchEngineButton.label;"/>
</form>
</div>
</div>
<div class="spacer"/>
<div id="launcher">
<button class="launchButton" id="downloads">&abouthome.downloadsButton.label;</button>
<button class="launchButton" id="bookmarks">&abouthome.bookmarksButton.label;</button>
<button class="launchButton" id="history">&abouthome.historyButton.label;</button>
<button class="launchButton" id="addons">&abouthome.addonsButton.label;</button>
<button class="launchButton" id="sync">&abouthome.syncButton.label;</button>
<button class="launchButton" id="settings">&abouthome.settingsButton.label;</button>
<div id="restorePreviousSessionSeparator"/>
<button class="launchButton" id="restorePreviousSession">&historyRestoreLastSession.label;</button>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View file

@ -0,0 +1,60 @@
/* 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/. */
/* Auto-recovery module.
* This module aims to catch fatal browser initialization errors and either
* automatically correct likely causes from them, or automatically restarting
* the browser in safe mode. This is hooked into the browser's "onload"
* event because it can be assumed that at that point, everything must
* have been properly initialized already.
*/
let Cc = Components.classes;
let Ci = Components.interfaces;
let Cu = Components.utils;
// Services = object with smart getters for common XPCOM services
Cu.import("resource://gre/modules/Services.jsm");
var browser_autoRecovery =
{
onLoad: function() {
var nsIAS = Ci.nsIAppStartup; // Application startup interface
if (typeof gBrowser === "undefined") {
// gBrowser should always be defined at this point, but if it is not, then most likely
// it is due to an incompatible or outdated language pack being installed and selected.
// In this case, we reset "general.useragent.locale" to try to recover browser startup.
if (Services.prefs.prefHasUserValue("general.useragent.locale")) {
// Restart automatically in en-US.
Services.prefs.clearUserPref("general.useragent.locale");
Cc["@mozilla.org/toolkit/app-startup;1"].getService(nsIAS).quit(nsIAS.eRestart | nsIAS.eAttemptQuit);
} else if (!Services.appinfo.inSafeMode) {
// gBrowser isn't defined, and we're not using a custom locale. Most likely
// a user-installed add-on causes issues here, so we restart in Safe Mode.
let RISM = Services.prompt.confirm(null, "Error",
"The Browser didn't start properly!\n"+
"This is usually caused by an add-on or misconfiguration.\n\n"+
"Restart in Safe Mode?");
if (RISM) {
Cc["@mozilla.org/toolkit/app-startup;1"].getService(nsIAS).restartInSafeMode(nsIAS.eRestart | nsIAS.eAttemptQuit);
} else {
// Force quit application
Cc["@mozilla.org/toolkit/app-startup;1"].getService(nsIAS).quit(nsIAS.eForceQuit);
}
}
// Something else caused this issue and we're already in Safe Mode, so we return
// without doing anything else, and let normal error handling take place.
return;
} // gBrowser undefined
// Other checks than gBrowser undefined can go here!
// Remove our listener, since we don't want this to fire on every load.
window.removeEventListener("load", browser_autoRecovery.onLoad, false);
}
};
window.addEventListener("load", browser_autoRecovery.onLoad, false);

View file

@ -0,0 +1,12 @@
<?xml version="1.0"?>
<overlay
id="autorecovery"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/x-javascript" src="chrome://browser/content/autorecovery.js"/>
<!-- This is an empty overlay to allow separation of the script into its
own context (needed for locale issues preventing browser start) -->
</overlay>

View file

@ -0,0 +1,100 @@
<?xml version="1.0"?>
# 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 overlay [
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
%brandDTD;
<!ENTITY % baseMenuOverlayDTD SYSTEM "chrome://browser/locale/baseMenuOverlay.dtd">
%baseMenuOverlayDTD;
]>
<overlay id="baseMenuOverlay"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
#ifdef XP_MACOSX
<!-- nsMenuBarX hides these and uses them to build the Application menu.
When using Carbon widgets for Mac OS X widgets, some of these are not
used as they only apply to Cocoa widget builds. All version of Firefox
through Firefox 2 will use Carbon widgets. -->
<menupopup id="menu_ToolsPopup">
<menuitem id="menu_preferences" label="&preferencesCmdMac.label;" key="key_preferencesCmdMac" oncommand="openPreferences();"/>
<menuitem id="menu_mac_services" label="&servicesMenuMac.label;"/>
<menuitem id="menu_mac_hide_app" label="&hideThisAppCmdMac.label;" key="key_hideThisAppCmdMac"/>
<menuitem id="menu_mac_hide_others" label="&hideOtherAppsCmdMac.label;" key="key_hideOtherAppsCmdMac"/>
<menuitem id="menu_mac_show_all" label="&showAllAppsCmdMac.label;"/>
</menupopup>
<!-- Mac window menu -->
#include ../../../toolkit/content/macWindowMenu.inc
#endif
#ifdef XP_WIN
<menu id="helpMenu"
label="&helpMenuWin.label;"
accesskey="&helpMenuWin.accesskey;">
#else
<menu id="helpMenu"
label="&helpMenu.label;"
accesskey="&helpMenu.accesskey;">
#endif
<menupopup id="menu_HelpPopup" onpopupshowing="buildHelpMenu();">
<menuitem id="menu_openHelp"
oncommand="openHelpLink('firefox-help')"
onclick="checkForMiddleClick(this, event);"
label="&productHelp.label;"
accesskey="&productHelp.accesskey;"
#ifdef XP_MACOSX
key="key_openHelpMac"/>
#else
/>
#endif
<menuitem id="troubleShooting"
accesskey="&helpTroubleshootingInfo.accesskey;"
label="&helpTroubleshootingInfo.label;"
oncommand="openTroubleshootingPage()"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="feedbackPage"
accesskey="&helpFeedbackPage.accesskey;"
label="&helpFeedbackPage.label;"
oncommand="openFeedbackPage()"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="helpSafeMode"
accesskey="&helpSafeMode.accesskey;"
label="&helpSafeMode.label;"
oncommand="restart(true);"/>
<menuseparator id="aboutSeparator"/>
<menuitem id="aboutName"
accesskey="&aboutProduct.accesskey;"
label="&aboutProduct.label;"
oncommand="openAboutDialog();"/>
</menupopup>
</menu>
<keyset id="baseMenuKeyset">
#ifdef XP_MACOSX
<key id="key_openHelpMac"
oncommand="openHelpLink('firefox-osxkey');"
key="&helpMac.commandkey;"
modifiers="accel"/>
<!-- These are used to build the Application menu under Cocoa widgets -->
<key id="key_preferencesCmdMac"
key="&preferencesCmdMac.commandkey;"
modifiers="accel"/>
<key id="key_hideThisAppCmdMac"
key="&hideThisAppCmdMac.commandkey;"
modifiers="accel"/>
<key id="key_hideOtherAppsCmdMac"
key="&hideOtherAppsCmdMac.commandkey;"
modifiers="accel,alt"/>
#endif
</keyset>
<stringbundleset id="stringbundleset">
<stringbundle id="bundle_browser" src="chrome://browser/locale/browser.properties"/>
<stringbundle id="bundle_browser_region" src="chrome://browser-region/locale/region.properties"/>
</stringbundleset>
</overlay>

View file

@ -0,0 +1,193 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html [
<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
%htmlDTD;
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
%globalDTD;
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
%brandDTD;
<!ENTITY % blockedSiteDTD SYSTEM "chrome://browser/locale/safebrowsing/phishing-afterload-warning-message.dtd">
%blockedSiteDTD;
]>
<!-- 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/. -->
<html xmlns="http://www.w3.org/1999/xhtml" class="blacklist">
<head>
<link rel="stylesheet" href="chrome://global/skin/netError.css" type="text/css" media="all" />
<link rel="icon" type="image/png" id="favicon" href="chrome://global/skin/icons/blacklist_favicon.png"/>
<script type="application/javascript"><![CDATA[
// Error url MUST be formatted like this:
// about:blocked?e=error_code&u=url
// Note that this file uses document.documentURI to get
// the URL (with the format from above). This is because
// document.location.href gets the current URI off the docshell,
// which is the URL displayed in the location bar, i.e.
// the URI that the user attempted to load.
function getErrorCode()
{
var url = document.documentURI;
var error = url.search(/e\=/);
var duffUrl = url.search(/\&u\=/);
return decodeURIComponent(url.slice(error + 2, duffUrl));
}
function getURL()
{
var url = document.documentURI;
var match = url.match(/&u=([^&]+)&/);
// match == null if not found; if so, return an empty string
// instead of what would turn out to be portions of the URI
if (!match)
return "";
url = decodeURIComponent(match[1]);
// If this is a view-source page, then get then real URI of the page
if (url.startsWith("view-source:"))
url = url.slice(12);
return url;
}
/**
* Attempt to get the hostname via document.location. Fail back
* to getURL so that we always return something meaningful.
*/
function getHostString()
{
try {
return document.location.hostname;
} catch (e) {
return getURL();
}
}
function initPage()
{
// Handoff to the appropriate initializer, based on error code
switch (getErrorCode()) {
case "malwareBlocked" :
initPage_malware();
break;
case "phishingBlocked" :
initPage_phishing();
break;
}
}
/**
* Initialize custom strings and functionality for blocked malware case
*/
function initPage_malware()
{
// Remove phishing strings
var el = document.getElementById("errorTitleText_phishing");
el.parentNode.removeChild(el);
el = document.getElementById("errorShortDescText_phishing");
el.parentNode.removeChild(el);
el = document.getElementById("errorLongDescText_phishing");
el.parentNode.removeChild(el);
// Set sitename
document.getElementById("malware_sitename").textContent = getHostString();
document.title = document.getElementById("errorTitleText_malware")
.innerHTML;
}
/**
* Initialize custom strings and functionality for blocked phishing case
*/
function initPage_phishing()
{
// Remove malware strings
var el = document.getElementById("errorTitleText_malware");
el.parentNode.removeChild(el);
el = document.getElementById("errorShortDescText_malware");
el.parentNode.removeChild(el);
el = document.getElementById("errorLongDescText_malware");
el.parentNode.removeChild(el);
// Set sitename
document.getElementById("phishing_sitename").textContent = getHostString();
document.title = document.getElementById("errorTitleText_phishing")
.innerHTML;
}
]]></script>
<style type="text/css">
/* Style warning button to look like a small text link in the
bottom right. This is preferable to just using a text link
since there is already a mechanism in browser.js for trapping
oncommand events from unprivileged chrome pages (BrowserOnCommand).*/
#ignoreWarningButton {
-moz-appearance: none;
background: transparent;
border: none;
color: white; /* Hard coded because netError.css forces this page's background to dark red */
text-decoration: underline;
margin: 0;
padding: 0;
position: relative;
top: 23px;
left: 20px;
font-size: smaller;
}
#ignoreWarning {
text-align: right;
}
</style>
</head>
<body dir="&locale.dir;">
<div id="errorPageContainer">
<!-- Error Title -->
<div id="errorTitle">
<h1 id="errorTitleText_phishing">&safeb.blocked.phishingPage.title;</h1>
<h1 id="errorTitleText_malware">&safeb.blocked.malwarePage.title;</h1>
</div>
<div id="errorLongContent">
<!-- Short Description -->
<div id="errorShortDesc">
<p id="errorShortDescText_phishing">&safeb.blocked.phishingPage.shortDesc;</p>
<p id="errorShortDescText_malware">&safeb.blocked.malwarePage.shortDesc;</p>
</div>
<!-- Long Description -->
<div id="errorLongDesc">
<p id="errorLongDescText_phishing">&safeb.blocked.phishingPage.longDesc;</p>
<p id="errorLongDescText_malware">&safeb.blocked.malwarePage.longDesc;</p>
</div>
<!-- Action buttons -->
<div id="buttons">
<!-- Commands handled in browser.js -->
<button id="getMeOutButton">&safeb.palm.accept.label;</button>
<button id="reportButton">&safeb.palm.reportPage.label;</button>
</div>
</div>
<div id="ignoreWarning">
<button id="ignoreWarningButton">&safeb.palm.decline.label;</button>
</div>
</div>
<!--
- Note: It is important to run the script this way, instead of using
- an onload handler. This is because error pages are loaded as
- LOAD_BACKGROUND, which means that onload handlers will not be executed.
-->
<script type="application/javascript">initPage();</script>
</body>
</html>

View file

@ -0,0 +1,536 @@
# -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# 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/.
// Removes a doorhanger notification if all of the installs it was notifying
// about have ended in some way.
function removeNotificationOnEnd(notification, installs) {
let count = installs.length;
function maybeRemove(install) {
install.removeListener(this);
if (--count == 0) {
// Check that the notification is still showing
let current = PopupNotifications.getNotification(notification.id, notification.browser);
if (current === notification)
notification.remove();
}
}
for (let install of installs) {
install.addListener({
onDownloadCancelled: maybeRemove,
onDownloadFailed: maybeRemove,
onInstallFailed: maybeRemove,
onInstallEnded: maybeRemove
});
}
}
const gXPInstallObserver = {
_findChildShell: function (aDocShell, aSoughtShell)
{
if (aDocShell == aSoughtShell)
return aDocShell;
var node = aDocShell.QueryInterface(Components.interfaces.nsIDocShellTreeItem);
for (var i = 0; i < node.childCount; ++i) {
var docShell = node.getChildAt(i);
docShell = this._findChildShell(docShell, aSoughtShell);
if (docShell == aSoughtShell)
return docShell;
}
return null;
},
_getBrowser: function (aDocShell)
{
for (let browser of gBrowser.browsers) {
if (this._findChildShell(browser.docShell, aDocShell))
return browser;
}
return null;
},
observe: function (aSubject, aTopic, aData)
{
var brandBundle = document.getElementById("bundle_brand");
var installInfo = aSubject.QueryInterface(Components.interfaces.amIWebInstallInfo);
var browser = installInfo.browser;
// Make sure the browser is still alive.
if (!browser || gBrowser.browsers.indexOf(browser) == -1)
return;
const anchorID = "addons-notification-icon";
var messageString, action;
var brandShortName = brandBundle.getString("brandShortName");
var notificationID = aTopic;
// Make notifications persist a minimum of 30 seconds
var options = {
timeout: Date.now() + 30000
};
switch (aTopic) {
case "addon-install-disabled":
notificationID = "xpinstall-disabled"
if (gPrefService.prefIsLocked("xpinstall.enabled")) {
messageString = gNavigatorBundle.getString("xpinstallDisabledMessageLocked");
buttons = [];
}
else {
messageString = gNavigatorBundle.getString("xpinstallDisabledMessage");
action = {
label: gNavigatorBundle.getString("xpinstallDisabledButton"),
accessKey: gNavigatorBundle.getString("xpinstallDisabledButton.accesskey"),
callback: function editPrefs() {
gPrefService.setBoolPref("xpinstall.enabled", true);
}
};
}
PopupNotifications.show(browser, notificationID, messageString, anchorID,
action, null, options);
break;
case "addon-install-origin-blocked": {
messageString = gNavigatorBundle.getFormattedString("xpinstallPromptWarningOrigin",
[brandShortName]);
let popup = PopupNotifications.show(browser, notificationID,
messageString, anchorID,
null, null, options);
removeNotificationOnEnd(popup, installInfo.installs);
break; }
case "addon-install-blocked":
let originatingHost;
try {
originatingHost = installInfo.originatingURI.host;
} catch (ex) {
// Need to deal with missing originatingURI and with about:/data: URIs more gracefully,
// see bug 1063418 - but for now, bail:
return;
}
messageString = gNavigatorBundle.getFormattedString("xpinstallPromptWarning",
[brandShortName, originatingHost]);
action = {
label: gNavigatorBundle.getString("xpinstallPromptAllowButton"),
accessKey: gNavigatorBundle.getString("xpinstallPromptAllowButton.accesskey"),
callback: function() {
installInfo.install();
}
};
let popup = PopupNotifications.show(browser, notificationID, messageString,
anchorID, action, null, options);
removeNotificationOnEnd(popup, installInfo.installs);
break;
case "addon-install-started":
var needsDownload = function needsDownload(aInstall) {
return aInstall.state != AddonManager.STATE_DOWNLOADED;
}
// If all installs have already been downloaded then there is no need to
// show the download progress
if (!installInfo.installs.some(needsDownload))
return;
notificationID = "addon-progress";
messageString = gNavigatorBundle.getString("addonDownloading");
messageString = PluralForm.get(installInfo.installs.length, messageString);
options.installs = installInfo.installs;
options.contentWindow = browser.contentWindow;
options.sourceURI = browser.currentURI;
options.eventCallback = function(aEvent) {
if (aEvent != "removed")
return;
options.contentWindow = null;
options.sourceURI = null;
};
PopupNotifications.show(browser, notificationID, messageString, anchorID,
null, null, options);
break;
case "addon-install-failed":
// TODO This isn't terribly ideal for the multiple failure case
for (let install of installInfo.installs) {
let host = (installInfo.originatingURI instanceof Ci.nsIStandardURL) &&
installInfo.originatingURI.host;
if (!host)
host = (install.sourceURI instanceof Ci.nsIStandardURL) &&
install.sourceURI.host;
let error = (host || install.error == 0) ? "addonError" : "addonLocalError";
if (install.error != 0)
error += install.error;
else if (install.addon.jetsdk)
error += "JetSDK";
else if (install.addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
error += "Blocklisted";
else
error += "Incompatible";
messageString = gNavigatorBundle.getString(error);
messageString = messageString.replace("#1", install.name);
if (host)
messageString = messageString.replace("#2", host);
messageString = messageString.replace("#3", brandShortName);
messageString = messageString.replace("#4", Services.appinfo.version);
PopupNotifications.show(browser, notificationID, messageString, anchorID,
action, null, options);
}
break;
case "addon-install-complete":
var needsRestart = installInfo.installs.some(function(i) {
return i.addon.pendingOperations != AddonManager.PENDING_NONE;
});
if (needsRestart) {
messageString = gNavigatorBundle.getString("addonsInstalledNeedsRestart");
action = {
label: gNavigatorBundle.getString("addonInstallRestartButton"),
accessKey: gNavigatorBundle.getString("addonInstallRestartButton.accesskey"),
callback: function() {
Application.restart();
}
};
}
else {
messageString = gNavigatorBundle.getString("addonsInstalled");
action = null;
}
messageString = PluralForm.get(installInfo.installs.length, messageString);
messageString = messageString.replace("#1", installInfo.installs[0].name);
messageString = messageString.replace("#2", installInfo.installs.length);
messageString = messageString.replace("#3", brandShortName);
// Remove notificaion on dismissal, since it's possible to cancel the
// install through the addons manager UI, making the "restart" prompt
// irrelevant.
options.removeOnDismissal = true;
PopupNotifications.show(browser, notificationID, messageString, anchorID,
action, null, options);
break;
}
}
};
/*
* When addons are installed/uninstalled, check and see if the number of items
* on the add-on bar changed:
* - If an add-on was installed, incrementing the count, show the bar.
* - If an add-on was uninstalled, and no more items are left, hide the bar.
*/
let AddonsMgrListener = {
get addonBar() document.getElementById("addon-bar"),
get statusBar() document.getElementById("status-bar"),
getAddonBarItemCount: function() {
// Take into account the contents of the status bar shim for the count.
var itemCount = this.statusBar.childNodes.length;
var defaultOrNoninteractive = this.addonBar.getAttribute("defaultset")
.split(",")
.concat(["separator", "spacer", "spring"]);
for (let item of this.addonBar.currentSet.split(",")) {
if (defaultOrNoninteractive.indexOf(item) == -1)
itemCount++;
}
return itemCount;
},
onInstalling: function(aAddon) {
this.lastAddonBarCount = this.getAddonBarItemCount();
},
onInstalled: function(aAddon) {
if (this.getAddonBarItemCount() > this.lastAddonBarCount)
setToolbarVisibility(this.addonBar, true);
},
onUninstalling: function(aAddon) {
this.lastAddonBarCount = this.getAddonBarItemCount();
},
onUninstalled: function(aAddon) {
if (this.getAddonBarItemCount() == 0)
setToolbarVisibility(this.addonBar, false);
},
onEnabling: function(aAddon) this.onInstalling(),
onEnabled: function(aAddon) this.onInstalled(),
onDisabling: function(aAddon) this.onUninstalling(),
onDisabled: function(aAddon) this.onUninstalled(),
};
var LightWeightThemeWebInstaller = {
handleEvent: function (event) {
switch (event.type) {
case "InstallBrowserTheme":
case "PreviewBrowserTheme":
case "ResetBrowserThemePreview":
// ignore requests from background tabs
if (event.target.ownerDocument.defaultView.top != content)
return;
}
switch (event.type) {
case "InstallBrowserTheme":
this._installRequest(event);
break;
case "PreviewBrowserTheme":
this._preview(event);
break;
case "ResetBrowserThemePreview":
this._resetPreview(event);
break;
case "pagehide":
case "TabSelect":
this._resetPreview();
break;
}
},
get _manager () {
var temp = {};
Cu.import("resource://gre/modules/LightweightThemeManager.jsm", temp);
delete this._manager;
return this._manager = temp.LightweightThemeManager;
},
_installRequest: function (event) {
var node = event.target;
var data = this._getThemeFromNode(node);
if (!data)
return;
if (this._isAllowed(node)) {
this._install(data);
return;
}
var allowButtonText =
gNavigatorBundle.getString("lwthemeInstallRequest.allowButton");
var allowButtonAccesskey =
gNavigatorBundle.getString("lwthemeInstallRequest.allowButton.accesskey");
var message =
gNavigatorBundle.getFormattedString("lwthemeInstallRequest.message",
[node.ownerDocument.location.host]);
var buttons = [{
label: allowButtonText,
accessKey: allowButtonAccesskey,
callback: function () {
LightWeightThemeWebInstaller._install(data);
}
}];
this._removePreviousNotifications();
var notificationBox = gBrowser.getNotificationBox();
var notificationBar =
notificationBox.appendNotification(message, "lwtheme-install-request", "",
notificationBox.PRIORITY_INFO_MEDIUM,
buttons);
notificationBar.persistence = 1;
},
_install: function (newLWTheme) {
var previousLWTheme = this._manager.currentTheme;
var listener = {
onEnabling: function(aAddon, aRequiresRestart) {
if (!aRequiresRestart)
return;
let messageString = gNavigatorBundle.getFormattedString("lwthemeNeedsRestart.message",
[aAddon.name], 1);
let action = {
label: gNavigatorBundle.getString("lwthemeNeedsRestart.button"),
accessKey: gNavigatorBundle.getString("lwthemeNeedsRestart.accesskey"),
callback: function () {
Application.restart();
}
};
let options = {
timeout: Date.now() + 30000
};
PopupNotifications.show(gBrowser.selectedBrowser, "addon-theme-change",
messageString, "addons-notification-icon",
action, null, options);
},
onEnabled: function(aAddon) {
LightWeightThemeWebInstaller._postInstallNotification(newLWTheme, previousLWTheme);
}
};
AddonManager.addAddonListener(listener);
this._manager.currentTheme = newLWTheme;
AddonManager.removeAddonListener(listener);
},
_postInstallNotification: function (newTheme, previousTheme) {
function text(id) {
return gNavigatorBundle.getString("lwthemePostInstallNotification." + id);
}
var buttons = [{
label: text("undoButton"),
accessKey: text("undoButton.accesskey"),
callback: function () {
LightWeightThemeWebInstaller._manager.forgetUsedTheme(newTheme.id);
LightWeightThemeWebInstaller._manager.currentTheme = previousTheme;
}
}, {
label: text("manageButton"),
accessKey: text("manageButton.accesskey"),
callback: function () {
BrowserOpenAddonsMgr("addons://list/theme");
}
}];
this._removePreviousNotifications();
var notificationBox = gBrowser.getNotificationBox();
var notificationBar =
notificationBox.appendNotification(text("message"),
"lwtheme-install-notification", "",
notificationBox.PRIORITY_INFO_MEDIUM,
buttons);
notificationBar.persistence = 1;
notificationBar.timeout = Date.now() + 20000; // 20 seconds
},
_removePreviousNotifications: function () {
var box = gBrowser.getNotificationBox();
["lwtheme-install-request",
"lwtheme-install-notification"].forEach(function (value) {
var notification = box.getNotificationWithValue(value);
if (notification)
box.removeNotification(notification);
});
},
_previewWindow: null,
_preview: function (event) {
if (!this._isAllowed(event.target))
return;
var data = this._getThemeFromNode(event.target);
if (!data)
return;
this._resetPreview();
this._previewWindow = event.target.ownerDocument.defaultView;
this._previewWindow.addEventListener("pagehide", this, true);
gBrowser.tabContainer.addEventListener("TabSelect", this, false);
this._manager.previewTheme(data);
},
_resetPreview: function (event) {
if (!this._previewWindow ||
event && !this._isAllowed(event.target))
return;
this._previewWindow.removeEventListener("pagehide", this, true);
this._previewWindow = null;
gBrowser.tabContainer.removeEventListener("TabSelect", this, false);
this._manager.resetPreview();
},
_isAllowed: function (node) {
var pm = Services.perms;
var uri = node.ownerDocument.documentURIObject;
return pm.testPermission(uri, "install") == pm.ALLOW_ACTION;
},
_getThemeFromNode: function (node) {
return this._manager.parseTheme(node.getAttribute("data-browsertheme"),
node.baseURI);
}
}
/*
* Listen for Lightweight Theme styling changes and update the browser's theme accordingly.
*/
let LightweightThemeListener = {
_modifiedStyles: [],
init: function () {
XPCOMUtils.defineLazyGetter(this, "styleSheet", function() {
for (let i = document.styleSheets.length - 1; i >= 0; i--) {
let sheet = document.styleSheets[i];
if (sheet.href == "chrome://browser/skin/browser-lightweightTheme.css")
return sheet;
}
});
Services.obs.addObserver(this, "lightweight-theme-styling-update", false);
Services.obs.addObserver(this, "lightweight-theme-optimized", false);
if (document.documentElement.hasAttribute("lwtheme"))
this.updateStyleSheet(document.documentElement.style.backgroundImage);
},
uninit: function () {
Services.obs.removeObserver(this, "lightweight-theme-styling-update");
Services.obs.removeObserver(this, "lightweight-theme-optimized");
},
/**
* Append the headerImage to the background-image property of all rulesets in
* browser-lightweightTheme.css.
*
* @param headerImage - a string containing a CSS image for the lightweight theme header.
*/
updateStyleSheet: function(headerImage) {
if (!this.styleSheet)
return;
this.substituteRules(this.styleSheet.cssRules, headerImage);
},
substituteRules: function(ruleList, headerImage, existingStyleRulesModified = 0) {
let styleRulesModified = 0;
for (let i = 0; i < ruleList.length; i++) {
let rule = ruleList[i];
if (rule instanceof Ci.nsIDOMCSSGroupingRule) {
// Add the number of modified sub-rules to the modified count
styleRulesModified += this.substituteRules(rule.cssRules, headerImage, existingStyleRulesModified + styleRulesModified);
} else if (rule instanceof Ci.nsIDOMCSSStyleRule) {
if (!rule.style.backgroundImage)
continue;
let modifiedIndex = existingStyleRulesModified + styleRulesModified;
if (!this._modifiedStyles[modifiedIndex])
this._modifiedStyles[modifiedIndex] = { backgroundImage: rule.style.backgroundImage };
rule.style.backgroundImage = this._modifiedStyles[modifiedIndex].backgroundImage + ", " + headerImage;
styleRulesModified++;
} else {
Cu.reportError("Unsupported rule encountered");
}
}
return styleRulesModified;
},
// nsIObserver
observe: function (aSubject, aTopic, aData) {
if ((aTopic != "lightweight-theme-styling-update" && aTopic != "lightweight-theme-optimized") ||
!this.styleSheet)
return;
if (aTopic == "lightweight-theme-optimized" && aSubject != window)
return;
let themeData = JSON.parse(aData);
if (!themeData)
return;
this.updateStyleSheet("url(" + themeData.headerURL + ")");
},
};

View file

@ -0,0 +1,394 @@
# -*- Mode: HTML -*-
# 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/.
<menupopup id="appmenu-popup"
onpopupshowing="if (event.target == this) {
updateEditUIVisibility();
#ifdef MOZ_SERVICES_SYNC
gSyncUI.updateUI();
#endif
return;
}
updateCharacterEncodingMenuState();
if (event.target.parentNode.parentNode.parentNode.parentNode == this)
this._currentPopup = event.target;">
<hbox>
<vbox id="appmenuPrimaryPane">
<menuitem id="appmenu_newTab_popup"
label="&tabCmd.label;"
command="cmd_newNavigatorTab"
key="key_newNavigatorTab"/>
<menuitem id="appmenu_newNavigator"
label="&newNavigatorCmd.label;"
command="cmd_newNavigator"
key="key_newNavigator"/>
<menuitem id="appmenu_newPrivateWindow"
class="menuitem-iconic menuitem-iconic-tooltip"
label="&newPrivateWindow.label;"
command="Tools:PrivateBrowsing"
key="key_privatebrowsing"/>
<menuitem label="&goOfflineCmd.label;"
id="appmenu_offlineModeRecovery"
type="checkbox"
observes="workOfflineMenuitemState"
oncommand="BrowserOffline.toggleOfflineStatus();"/>
<menuseparator class="appmenu-menuseparator"/>
<hbox>
<menuitem id="appmenu-edit-label"
label="&appMenuEdit.label;"
disabled="true"/>
<toolbarbutton id="appmenu-cut"
class="appmenu-edit-button"
command="cmd_cut"
onclick="if (!this.disabled) hidePopup();"
tooltiptext="&cutButton.tooltip;"/>
<toolbarbutton id="appmenu-copy"
class="appmenu-edit-button"
command="cmd_copy"
onclick="if (!this.disabled) hidePopup();"
tooltiptext="&copyButton.tooltip;"/>
<toolbarbutton id="appmenu-paste"
class="appmenu-edit-button"
command="cmd_paste"
onclick="if (!this.disabled) hidePopup();"
tooltiptext="&pasteButton.tooltip;"/>
<spacer flex="1"/>
<menu id="appmenu-editmenu">
<menupopup id="appmenu-editmenu-menupopup">
<menuitem id="appmenu-editmenu-cut"
class="menuitem-iconic"
label="&cutCmd.label;"
key="key_cut"
command="cmd_cut"/>
<menuitem id="appmenu-editmenu-copy"
class="menuitem-iconic"
label="&copyCmd.label;"
key="key_copy"
command="cmd_copy"/>
<menuitem id="appmenu-editmenu-paste"
class="menuitem-iconic"
label="&pasteCmd.label;"
key="key_paste"
command="cmd_paste"/>
<menuseparator/>
<menuitem id="appmenu-editmenu-undo"
label="&undoCmd.label;"
key="key_undo"
command="cmd_undo"/>
<menuitem id="appmenu-editmenu-redo"
label="&redoCmd.label;"
key="key_redo"
command="cmd_redo"/>
<menuseparator/>
<menuitem id="appmenu-editmenu-selectAll"
label="&selectAllCmd.label;"
key="key_selectAll"
command="cmd_selectAll"/>
<menuseparator/>
<menuitem id="appmenu-editmenu-delete"
label="&deleteCmd.label;"
key="key_delete"
command="cmd_delete"/>
</menupopup>
</menu>
</hbox>
<menuitem id="appmenu_find"
class="menuitem-tooltip"
label="&appMenuFind.label;"
command="cmd_find"
key="key_find"/>
<menuseparator class="appmenu-menuseparator"/>
<menuitem id="appmenu_openFile"
label="&openFileCmd.label;"
command="Browser:OpenFile"
key="openFileKb"/>
<menuitem id="appmenu_savePage"
class="menuitem-tooltip"
label="&savePageCmd.label;"
command="Browser:SavePage"
key="key_savePage"/>
<menuitem id="appmenu_sendLink"
label="&emailPageCmd.label;"
command="Browser:SendLink"/>
<splitmenu id="appmenu_print"
iconic="true"
label="&printCmd.label;"
command="cmd_print">
<menupopup>
<menuitem id="appmenu_print_popup"
class="menuitem-iconic"
label="&printCmd.label;"
command="cmd_print"
key="printKb"/>
<menuitem id="appmenu_printPreview"
label="&printPreviewCmd.label;"
command="cmd_printPreview"/>
<menuitem id="appmenu_printSetup"
label="&printSetupCmd.label;"
command="cmd_pageSetup"/>
</menupopup>
</splitmenu>
<menuseparator class="appmenu-menuseparator"/>
<splitmenu id="appmenu_webDeveloper"
command="Tools:DevToolbox"
label="&appMenuWebDeveloper.label;">
<menupopup id="appmenu_webDeveloper_popup">
#ifdef MOZ_DEVTOOLS
<menuitem id="appmenu_devToolbox"
observes="devtoolsMenuBroadcaster_DevToolbox"/>
<menuseparator id="appmenu_devtools_separator"/>
<menuitem id="appmenu_devToolbar"
observes="devtoolsMenuBroadcaster_DevToolbar"/>
<menuitem id="appmenu_chromeDebugger"
observes="devtoolsMenuBroadcaster_ChromeDebugger"/>
<menuitem id="appmenu_browserConsole"
observes="devtoolsMenuBroadcaster_BrowserConsole"/>
<menuitem id="appmenu_responsiveUI"
observes="devtoolsMenuBroadcaster_ResponsiveUI"/>
<menuitem id="appmenu_eyedropper"
observes="devtoolsMenuBroadcaster_Eyedropper"/>
<menuitem id="appmenu_scratchpad"
observes="devtoolsMenuBroadcaster_Scratchpad"/>
#endif
<menuitem id="appmenu_pageSource"
observes="devtoolsMenuBroadcaster_PageSource"/>
<menuitem id="appmenu_errorConsole"
observes="devtoolsMenuBroadcaster_ErrorConsole"/>
#ifdef MOZ_DEVTOOLS
<menuitem id="appmenu_devtools_connect"
observes="devtoolsMenuBroadcaster_connect"/>
#endif
<menuseparator id="appmenu_devToolsEndSeparator"/>
<menuitem id="appmenu_getMoreDevtools"
observes="devtoolsMenuBroadcaster_GetMoreTools"/>
<menuseparator/>
#define ID_PREFIX appmenu_developer_
#define OMIT_ACCESSKEYS
#include browser-charsetmenu.inc
#undef ID_PREFIX
#undef OMIT_ACCESSKEYS
<menuitem label="&goOfflineCmd.label;"
type="checkbox"
observes="workOfflineMenuitemState"
oncommand="BrowserOffline.toggleOfflineStatus();"/>
</menupopup>
</splitmenu>
<menuseparator class="appmenu-menuseparator"/>
#define ID_PREFIX appmenu_
#define OMIT_ACCESSKEYS
#include browser-charsetmenu.inc
#undef ID_PREFIX
#undef OMIT_ACCESSKEYS
<menuitem id="appmenu_fullScreen"
class="menuitem-tooltip"
label="&fullScreenCmd.label;"
type="checkbox"
observes="View:FullScreen"
key="key_fullScreen"/>
<menuitem id="appmenu_restart"
class="menuitem-iconic"
label="&appMenuRestart.label;"
command="cmd_restartApplication"/>
<menuitem id="appmenu-quit"
class="menuitem-iconic"
#ifdef XP_WIN
label="&quitApplicationCmdWin.label;"
#else
label="&quitApplicationCmd.label;"
#endif
command="cmd_quitApplication"/>
</vbox>
<vbox id="appmenuSecondaryPane">
<splitmenu id="appmenu_bookmarks"
iconic="true"
label="&bookmarksMenu.label;"
command="Browser:ShowAllBookmarks">
<menupopup id="appmenu_bookmarksPopup"
placespopup="true"
context="placesContext"
openInTabs="children"
oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
onpopupshowing="BookmarkingUI.onPopupShowing(event);
if (!this.parentNode._placesView)
new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
tooltip="bhTooltip"
popupsinherittooltip="true">
<menuitem id="appmenu_showAllBookmarks"
class="menuitem-iconic"
label="&organizeBookmarks.label;"
command="Browser:ShowAllBookmarks"
context=""
key="manBookmarkKb"/>
<menuseparator/>
<menuitem id="appmenu_bookmarkThisPage"
class="menuitem-iconic"
label="&bookmarkThisPageCmd.label;"
command="Browser:AddBookmarkAs"
key="addBookmarkAsKb"/>
<menuitem id="appmenu_subscribeToPage"
class="menuitem-iconic"
label="&subscribeToPageMenuitem.label;"
oncommand="return FeedHandler.subscribeToFeed(null, event);"
onclick="checkForMiddleClick(this, event);"
observes="singleFeedMenuitemState"/>
<menu id="appmenu_subscribeToPageMenu"
class="menu-iconic"
label="&subscribeToPageMenupopup.label;"
observes="multipleFeedsMenuState">
<menupopup id="appmenu_subscribeToPageMenupopup"
onpopupshowing="return FeedHandler.buildFeedList(event.target);"
oncommand="return FeedHandler.subscribeToFeed(null, event);"
onclick="checkForMiddleClick(this, event);"/>
</menu>
<menuseparator/>
<menu id="appmenu_bookmarksToolbar"
placesanonid="toolbar-autohide"
class="menu-iconic bookmark-item"
label="&personalbarCmd.label;"
container="true">
<menupopup id="appmenu_bookmarksToolbarPopup"
placespopup="true"
context="placesContext"
onpopupshowing="if (!this.parentNode._placesView)
new PlacesMenu(event, 'place:folder=TOOLBAR');"/>
</menu>
<menuseparator/>
<!-- Bookmarks menu items -->
<menuseparator builder="end"
class="hide-if-empty-places-result"/>
<menuitem id="appmenu_unsortedBookmarks"
class="menuitem-iconic"
label="&appMenuUnsorted.label;"
oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');"/>
</menupopup>
</splitmenu>
<splitmenu id="appmenu_history"
iconic="true"
label="&historyMenu.label;"
command="Browser:ShowAllHistory">
<menupopup id="appmenu_historyMenupopup"
placespopup="true"
context="placesContext"
oncommand="this.parentNode._placesView._onCommand(event);"
onclick="checkForMiddleClick(this, event);"
onpopupshowing="if (!this.parentNode._placesView)
new HistoryMenu(event);"
tooltip="bhTooltip"
popupsinherittooltip="true">
<menuitem id="appmenu_showAllHistory"
class="menuitem-iconic"
label="&showAllHistoryCmd2.label;"
command="Browser:ShowAllHistory"
key="showAllHistoryKb"/>
<menuseparator/>
<menuitem id="appmenu_sanitizeHistory"
class="menuitem-iconic"
label="&clearRecentHistory.label;"
key="key_sanitize"
command="Tools:Sanitize"/>
<menuseparator class="hide-if-empty-places-result"/>
#ifdef MOZ_SERVICES_SYNC
<menuitem id="appmenu_sync-tabs"
class="syncTabsMenuItem"
label="&syncTabsMenu2.label;"
oncommand="BrowserOpenSyncTabs();"
disabled="true"/>
#endif
<menuitem id="appmenu_restoreLastSession"
label="&historyRestoreLastSession.label;"
command="Browser:RestoreLastSession"/>
<menu id="appmenu_recentlyClosedTabsMenu"
class="recentlyClosedTabsMenu"
label="&historyUndoMenu.label;"
disabled="true">
<menupopup id="appmenu_recentlyClosedTabsMenupopup"
onpopupshowing="document.getElementById('appmenu_history')._placesView.populateUndoSubmenu();"/>
</menu>
<menu id="appmenu_recentlyClosedWindowsMenu"
class="recentlyClosedWindowsMenu"
label="&historyUndoWindowMenu.label;"
disabled="true">
<menupopup id="appmenu_recentlyClosedWindowsMenupopup"
onpopupshowing="document.getElementById('appmenu_history')._placesView.populateUndoWindowSubmenu();"/>
</menu>
<menuseparator/>
</menupopup>
</splitmenu>
<menuitem id="appmenu_downloads"
class="menuitem-tooltip"
label="&downloads.label;"
command="Tools:Downloads"
key="key_openDownloads"/>
<spacer id="appmenuSecondaryPane-spacer"/>
<menuitem id="appmenu_addons"
class="menuitem-iconic menuitem-iconic-tooltip"
label="&addons.label;"
command="Tools:Addons"
key="key_openAddons"/>
<menuitem id="appmenu_permissions"
class="menuitem-iconic"
label="&permissions.label;"
command="Tools:Permissions"
key="key_openPermissions"/>
#ifdef MOZ_SERVICES_SYNC
<!-- only one of sync-setup or sync-syncnow will be showing at once -->
<menuitem id="sync-setup-appmenu"
label="&syncSetup.label;"
observes="sync-setup-state"
oncommand="gSyncUI.openSetup()"/>
<menuitem id="sync-syncnowitem-appmenu"
label="&syncSyncNowItem.label;"
observes="sync-syncnow-state"
oncommand="gSyncUI.doSync(event);"/>
#endif
<splitmenu id="appmenu_customize"
label="&preferencesCmd2.label;"
oncommand="openPreferences();">
<menupopup id="appmenu_customizeMenu"
onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('appmenu_toggleToolbarsSeparator'));">
<menuitem id="appmenu_preferences"
label="&preferencesCmd2.label;"
oncommand="openPreferences();"/>
<menuseparator/>
<menuseparator id="appmenu_toggleToolbarsSeparator"/>
<menuitem id="appmenu_toggleTabsOnTop"
label="&viewTabsOnTop.label;"
type="checkbox"
command="cmd_ToggleTabsOnTop"/>
<menuitem id="appmenu_toolbarLayout"
label="&appMenuToolbarLayout.label;"
command="cmd_CustomizeToolbars"/>
</menupopup>
</splitmenu>
<splitmenu id="appmenu_help"
label="&helpMenu.label;"
oncommand="openHelpLink('firefox-help')">
<menupopup id="appmenu_helpMenupopup">
<menuitem id="appmenu_openHelp"
label="&helpMenu.label;"
oncommand="openHelpLink('firefox-help')"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="appmenu_troubleshootingInfo"
label="&helpTroubleshootingInfo.label;"
oncommand="openTroubleshootingPage()"
onclick="checkForMiddleClick(this,event);"/>
<menuitem id="appmenu_feedbackPage"
label="&helpFeedbackPage.label;"
oncommand="openFeedbackPage()"
onclick="checkForMiddleClick(this, event);"/>
<menuseparator/>
<menuitem id="appmenu_safeMode"
label="&appMenuSafeMode.label;"
oncommand="restart(true);"/>
<menuseparator/>
<menuitem id="appmenu_about"
label="&aboutProduct.label;"
oncommand="openAboutDialog();"/>
</menupopup>
</splitmenu>
</vbox>
</hbox>
</menupopup>

View file

@ -0,0 +1,62 @@
# 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/.
#filter substitution
#expand <menu id="__ID_PREFIX__charsetMenu"
label="&charsetMenu.label;"
#ifndef OMIT_ACCESSKEYS
accesskey="&charsetMenu.accesskey;"
#endif
oncommand="MultiplexHandler(event)"
#ifdef OMIT_ACCESSKEYS
#expand onpopupshowing="CharsetMenu.build(event, '__ID_PREFIX__');"
#else
#expand onpopupshowing="CharsetMenu.build(event, '__ID_PREFIX__', true);"
#endif
onpopupshown="UpdateMenus(event);">
<menupopup>
<menu label="&charsetMenuAutodet.label;"
#ifndef OMIT_ACCESSKEYS
accesskey="&charsetMenuAutodet.accesskey;"
#endif
>
<menupopup>
<menuitem type="radio"
name="detectorGroup"
#expand id="__ID_PREFIX__chardet.off"
label="&charsetMenuAutodet.off.label;"
#ifndef OMIT_ACCESSKEYS
accesskey="&charsetMenuAutodet.off.accesskey;"
#endif
/>
<menuitem type="radio"
name="detectorGroup"
#expand id="__ID_PREFIX__chardet.ja_parallel_state_machine"
label="&charsetMenuAutodet.ja.label;"
#ifndef OMIT_ACCESSKEYS
accesskey="&charsetMenuAutodet.ja.accesskey;"
#endif
/>
<menuitem type="radio"
name="detectorGroup"
#expand id="__ID_PREFIX__chardet.ruprob"
label="&charsetMenuAutodet.ru.label;"
#ifndef OMIT_ACCESSKEYS
accesskey="&charsetMenuAutodet.ru.accesskey;"
#endif
/>
<menuitem type="radio"
name="detectorGroup"
#expand id="__ID_PREFIX__chardet.ukprob"
label="&charsetMenuAutodet.uk.label;"
#ifndef OMIT_ACCESSKEYS
accesskey="&charsetMenuAutodet.uk.accesskey;"
#endif
/>
</menupopup>
</menu>
<menuseparator/>
</menupopup>
</menu>

View file

@ -0,0 +1,379 @@
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
# 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/.
<menuseparator id="page-menu-separator"/>
<menuitem id="spell-no-suggestions"
disabled="true"
label="&spellNoSuggestions.label;"/>
<menuitem id="spell-add-to-dictionary"
label="&spellAddToDictionary.label;"
accesskey="&spellAddToDictionary.accesskey;"
oncommand="InlineSpellCheckerUI.addToDictionary();"/>
<menuitem id="spell-undo-add-to-dictionary"
label="&spellUndoAddToDictionary.label;"
accesskey="&spellUndoAddToDictionary.accesskey;"
oncommand="InlineSpellCheckerUI.undoAddToDictionary();" />
<menuseparator id="spell-suggestions-separator"/>
<menuitem id="context-openlinkintab"
label="&openLinkCmdInTab.label;"
accesskey="&openLinkCmdInTab.accesskey;"
oncommand="gContextMenu.openLinkInTab();"/>
<menuitem id="context-openlink"
label="&openLinkCmd.label;"
accesskey="&openLinkCmd.accesskey;"
oncommand="gContextMenu.openLink();"/>
<menuitem id="context-openlinkprivate"
label="&openLinkInPrivateWindowCmd.label;"
accesskey="&openLinkInPrivateWindowCmd.accesskey;"
oncommand="gContextMenu.openLinkInPrivateWindow();"/>
<menuitem id="context-openlinkincurrent"
label="&openLinkCmdInCurrent.label;"
accesskey="&openLinkCmdInCurrent.accesskey;"
oncommand="gContextMenu.openLinkInCurrent();"/>
<menuseparator id="context-sep-open"/>
<menuitem id="context-bookmarklink"
label="&bookmarkThisLinkCmd.label;"
accesskey="&bookmarkThisLinkCmd.accesskey;"
oncommand="gContextMenu.bookmarkLink();"/>
<menuitem id="context-savelink"
label="&saveLinkCmd.label;"
accesskey="&saveLinkCmd.accesskey;"
oncommand="gContextMenu.saveLink();"/>
<menuitem id="context-sendlink"
label="&sendLinkCmd.label;"
accesskey="&sendLinkCmd.accesskey;"
oncommand="gContextMenu.sendLink();"/>
<menuitem id="context-copyemail"
label="&copyEmailCmd.label;"
accesskey="&copyEmailCmd.accesskey;"
oncommand="gContextMenu.copyEmail();"/>
<menuitem id="context-copylink"
label="&copyLinkCmd.label;"
accesskey="&copyLinkCmd.accesskey;"
oncommand="goDoCommand('cmd_copyLink');"/>
<menuseparator id="context-sep-copylink"/>
<menuitem id="context-media-play"
label="&mediaPlay.label;"
accesskey="&mediaPlay.accesskey;"
oncommand="gContextMenu.mediaCommand('play');"/>
<menuitem id="context-media-pause"
label="&mediaPause.label;"
accesskey="&mediaPause.accesskey;"
oncommand="gContextMenu.mediaCommand('pause');"/>
<menuitem id="context-media-mute"
label="&mediaMute.label;"
accesskey="&mediaMute.accesskey;"
oncommand="gContextMenu.mediaCommand('mute');"/>
<menuitem id="context-media-unmute"
label="&mediaUnmute.label;"
accesskey="&mediaUnmute.accesskey;"
oncommand="gContextMenu.mediaCommand('unmute');"/>
<menu id="context-media-playbackrate" label="&mediaPlaybackRate.label;" accesskey="&mediaPlaybackRate.accesskey;">
<menupopup>
<menuitem id="context-media-playbackrate-050x"
label="&mediaPlaybackRate050x.label;"
accesskey="&mediaPlaybackRate050x.accesskey;"
type="radio"
name="playbackrate"
oncommand="gContextMenu.mediaCommand('playbackRate', 0.5);"/>
<menuitem id="context-media-playbackrate-100x"
label="&mediaPlaybackRate100x.label;"
accesskey="&mediaPlaybackRate100x.accesskey;"
type="radio"
name="playbackrate"
checked="true"
oncommand="gContextMenu.mediaCommand('playbackRate', 1.0);"/>
<menuitem id="context-media-playbackrate-150x"
label="&mediaPlaybackRate150x.label;"
accesskey="&mediaPlaybackRate150x.accesskey;"
type="radio"
name="playbackrate"
oncommand="gContextMenu.mediaCommand('playbackRate', 1.5);"/>
<menuitem id="context-media-playbackrate-200x"
label="&mediaPlaybackRate200x.label;"
accesskey="&mediaPlaybackRate200x.accesskey;"
type="radio"
name="playbackrate"
oncommand="gContextMenu.mediaCommand('playbackRate', 2.0);"/>
</menupopup>
</menu>
<menuitem id="context-media-showcontrols"
label="&mediaShowControls.label;"
accesskey="&mediaShowControls.accesskey;"
oncommand="gContextMenu.mediaCommand('showcontrols');"/>
<menuitem id="context-media-hidecontrols"
label="&mediaHideControls.label;"
accesskey="&mediaHideControls.accesskey;"
oncommand="gContextMenu.mediaCommand('hidecontrols');"/>
<menuitem id="context-video-showstats"
accesskey="&videoShowStats.accesskey;"
label="&videoShowStats.label;"
oncommand="gContextMenu.mediaCommand('showstats');"/>
<menuitem id="context-video-hidestats"
accesskey="&videoHideStats.accesskey;"
label="&videoHideStats.label;"
oncommand="gContextMenu.mediaCommand('hidestats');"/>
<menuitem id="context-video-fullscreen"
accesskey="&videoFullScreen.accesskey;"
label="&videoFullScreen.label;"
oncommand="gContextMenu.fullScreenVideo();"/>
<menuitem id="context-leave-dom-fullscreen"
accesskey="&leaveDOMFullScreen.accesskey;"
label="&leaveDOMFullScreen.label;"
oncommand="gContextMenu.leaveDOMFullScreen();"/>
<menuseparator id="context-media-sep-commands"/>
<menuitem id="context-reloadimage"
label="&reloadImageCmd.label;"
accesskey="&reloadImageCmd.accesskey;"
oncommand="gContextMenu.reloadImage();"/>
<menuitem id="context-viewimage"
label="&viewImageCmd.label;"
accesskey="&viewImageCmd.accesskey;"
oncommand="gContextMenu.viewMedia(event);"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="context-viewvideo"
label="&viewVideoCmd.label;"
accesskey="&viewVideoCmd.accesskey;"
oncommand="gContextMenu.viewMedia(event);"
onclick="checkForMiddleClick(this, event);"/>
#ifdef CONTEXT_COPY_IMAGE_CONTENTS
<menuitem id="context-copyimage-contents"
label="&copyImageContentsCmd.label;"
accesskey="&copyImageContentsCmd.accesskey;"
oncommand="goDoCommand('cmd_copyImage');"/>
#endif
<menuitem id="context-copyimage"
label="&copyImageCmd.label;"
accesskey="&copyImageCmd.accesskey;"
oncommand="gContextMenu.copyMediaLocation();"/>
<menuitem id="context-copyvideourl"
label="&copyVideoURLCmd.label;"
accesskey="&copyVideoURLCmd.accesskey;"
oncommand="gContextMenu.copyMediaLocation();"/>
<menuitem id="context-copyaudiourl"
label="&copyAudioURLCmd.label;"
accesskey="&copyAudioURLCmd.accesskey;"
oncommand="gContextMenu.copyMediaLocation();"/>
<menuseparator id="context-sep-copyimage"/>
<menuitem id="context-saveimage"
label="&saveImageCmd.label;"
accesskey="&saveImageCmd.accesskey;"
oncommand="gContextMenu.saveMedia();"/>
<menuitem id="context-sendimage"
label="&emailImageCmd.label;"
accesskey="&emailImageCmd.accesskey;"
oncommand="gContextMenu.sendMedia();"/>
<menuitem id="context-setDesktopBackground"
label="&setDesktopBackgroundCmd.label;"
accesskey="&setDesktopBackgroundCmd.accesskey;"
oncommand="gContextMenu.setDesktopBackground();"/>
<menuitem id="context-viewimageinfo"
label="&viewImageInfoCmd.label;"
accesskey="&viewImageInfoCmd.accesskey;"
oncommand="gContextMenu.viewImageInfo();"/>
<menuitem id="context-savevideo"
label="&saveVideoCmd.label;"
accesskey="&saveVideoCmd.accesskey;"
oncommand="gContextMenu.saveMedia();"/>
<menuitem id="context-saveaudio"
label="&saveAudioCmd.label;"
accesskey="&saveAudioCmd.accesskey;"
oncommand="gContextMenu.saveMedia();"/>
<menuitem id="context-video-saveimage"
accesskey="&videoSaveImage.accesskey;"
label="&videoSaveImage.label;"
oncommand="gContextMenu.saveVideoFrameAsImage();"/>
<menuitem id="context-sendvideo"
label="&emailVideoCmd.label;"
accesskey="&emailVideoCmd.accesskey;"
oncommand="gContextMenu.sendMedia();"/>
<menuitem id="context-sendaudio"
label="&emailAudioCmd.label;"
accesskey="&emailAudioCmd.accesskey;"
oncommand="gContextMenu.sendMedia();"/>
<menuitem id="context-ctp-play"
label="&playPluginCmd.label;"
accesskey="&playPluginCmd.accesskey;"
oncommand="gContextMenu.playPlugin();"/>
<menuitem id="context-ctp-hide"
label="&hidePluginCmd.label;"
accesskey="&hidePluginCmd.accesskey;"
oncommand="gContextMenu.hidePlugin();"/>
<menuseparator id="context-sep-ctp"/>
<menuitem id="context-back"
label="&backCmd.label;"
accesskey="&backCmd.accesskey;"
command="Browser:BackOrBackDuplicate"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="context-forward"
label="&forwardCmd.label;"
accesskey="&forwardCmd.accesskey;"
command="Browser:ForwardOrForwardDuplicate"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="context-reload"
label="&reloadCmd.label;"
accesskey="&reloadCmd.accesskey;"
oncommand="gContextMenu.reload(event);"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="context-stop"
label="&stopCmd.label;"
accesskey="&stopCmd.accesskey;"
command="Browser:Stop"/>
<menuseparator id="context-sep-stop"/>
<menuitem id="context-bookmarkpage"
label="&bookmarkPageCmd2.label;"
accesskey="&bookmarkPageCmd2.accesskey;"
oncommand="gContextMenu.bookmarkThisPage();"/>
<menuitem id="context-savepage"
label="&savePageCmd.label;"
accesskey="&savePageCmd.accesskey2;"
oncommand="gContextMenu.savePageAs();"/>
<menuitem id="context-sendpage"
label="&sendPageCmd.label;"
accesskey="&sendPageCmd.accesskey;"
oncommand="gContextMenu.sendPage();"/>
<menuseparator id="context-sep-viewbgimage"/>
<menuitem id="context-viewbgimage"
label="&viewBGImageCmd.label;"
accesskey="&viewBGImageCmd.accesskey;"
oncommand="gContextMenu.viewBGImage(event);"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="context-undo"
label="&undoCmd.label;"
accesskey="&undoCmd.accesskey;"
command="cmd_undo"/>
<menuseparator id="context-sep-undo"/>
<menuitem id="context-cut"
label="&cutCmd.label;"
accesskey="&cutCmd.accesskey;"
command="cmd_cut"/>
<menuitem id="context-copy"
label="&copyCmd.label;"
accesskey="&copyCmd.accesskey;"
command="cmd_copy"/>
<menuitem id="context-paste"
label="&pasteCmd.label;"
accesskey="&pasteCmd.accesskey;"
command="cmd_paste"/>
<menuitem id="context-delete"
label="&deleteCmd.label;"
accesskey="&deleteCmd.accesskey;"
command="cmd_delete"/>
<menuseparator id="context-sep-paste"/>
<menuitem id="context-selectall"
label="&selectAllCmd.label;"
accesskey="&selectAllCmd.accesskey;"
command="cmd_selectAll"/>
<menuseparator id="context-sep-selectall"/>
<menuitem id="context-keywordfield"
label="&keywordfield.label;"
accesskey="&keywordfield.accesskey;"
oncommand="AddKeywordForSearchField();"/>
<menuitem id="context-searchselect"
oncommand="BrowserSearch.loadSearchFromContext(this.searchTerms);"/>
<menuseparator id="frame-sep"/>
<menu id="frame" label="&thisFrameMenu.label;" accesskey="&thisFrameMenu.accesskey;">
<menupopup>
<menuitem id="context-showonlythisframe"
label="&showOnlyThisFrameCmd.label;"
accesskey="&showOnlyThisFrameCmd.accesskey;"
oncommand="gContextMenu.showOnlyThisFrame();"/>
<menuitem id="context-openframeintab"
label="&openFrameCmdInTab.label;"
accesskey="&openFrameCmdInTab.accesskey;"
oncommand="gContextMenu.openFrameInTab();"/>
<menuitem id="context-openframe"
label="&openFrameCmd.label;"
accesskey="&openFrameCmd.accesskey;"
oncommand="gContextMenu.openFrame();"/>
<menuseparator id="open-frame-sep"/>
<menuitem id="context-reloadframe"
label="&reloadFrameCmd.label;"
accesskey="&reloadFrameCmd.accesskey;"
oncommand="gContextMenu.reloadFrame();"/>
<menuseparator/>
<menuitem id="context-bookmarkframe"
label="&bookmarkThisFrameCmd.label;"
accesskey="&bookmarkThisFrameCmd.accesskey;"
oncommand="gContextMenu.addBookmarkForFrame();"/>
<menuitem id="context-saveframe"
label="&saveFrameCmd.label;"
accesskey="&saveFrameCmd.accesskey;"
oncommand="gContextMenu.saveFrame();"/>
<menuseparator/>
<menuitem id="context-printframe"
label="&printFrameCmd.label;"
accesskey="&printFrameCmd.accesskey;"
oncommand="gContextMenu.printFrame();"/>
<menuseparator/>
<menuitem id="context-viewframesource"
label="&viewFrameSourceCmd.label;"
accesskey="&viewFrameSourceCmd.accesskey;"
oncommand="gContextMenu.viewFrameSource();"
observes="isFrameImage"/>
<menuitem id="context-viewframeinfo"
label="&viewFrameInfoCmd.label;"
accesskey="&viewFrameInfoCmd.accesskey;"
oncommand="gContextMenu.viewFrameInfo();"/>
</menupopup>
</menu>
<menuitem id="context-viewpartialsource-selection"
label="&viewPartialSourceForSelectionCmd.label;"
accesskey="&viewPartialSourceCmd.accesskey;"
oncommand="gContextMenu.viewPartialSource('selection');"
observes="isImage"/>
<menuitem id="context-viewpartialsource-mathml"
label="&viewPartialSourceForMathMLCmd.label;"
accesskey="&viewPartialSourceCmd.accesskey;"
oncommand="gContextMenu.viewPartialSource('mathml');"
observes="isImage"/>
<menuseparator id="context-sep-viewsource"/>
<menuitem id="context-viewsource"
label="&viewPageSourceCmd.label;"
accesskey="&viewPageSourceCmd.accesskey;"
oncommand="BrowserViewSourceOfDocument(gContextMenu.browser.contentDocument);"
observes="isImage"/>
<menuitem id="context-viewinfo"
label="&viewPageInfoCmd.label;"
accesskey="&viewPageInfoCmd.accesskey;"
oncommand="gContextMenu.viewInfo();"/>
<menuseparator id="spell-separator"/>
<menuitem id="spell-check-enabled"
label="&spellCheckToggle.label;"
type="checkbox"
accesskey="&spellCheckToggle.accesskey;"
oncommand="InlineSpellCheckerUI.toggleEnabled();"/>
<menuitem id="spell-add-dictionaries-main"
label="&spellAddDictionaries.label;"
accesskey="&spellAddDictionaries.accesskey;"
oncommand="gContextMenu.addDictionaries();"/>
<menu id="spell-dictionaries"
label="&spellDictionaries.label;"
accesskey="&spellDictionaries.accesskey;">
<menupopup id="spell-dictionaries-menu">
<menuseparator id="spell-language-separator"/>
<menuitem id="spell-add-dictionaries"
label="&spellAddDictionaries.label;"
accesskey="&spellAddDictionaries.accesskey;"
oncommand="gContextMenu.addDictionaries();"/>
</menupopup>
</menu>
<menuseparator hidden="true" id="context-sep-bidi"/>
<menuitem hidden="true" id="context-bidi-text-direction-toggle"
label="&bidiSwitchTextDirectionItem.label;"
accesskey="&bidiSwitchTextDirectionItem.accesskey;"
command="cmd_switchTextDirection"/>
<menuitem hidden="true" id="context-bidi-page-direction-toggle"
label="&bidiSwitchPageDirectionItem.label;"
accesskey="&bidiSwitchPageDirectionItem.accesskey;"
oncommand="gContextMenu.switchPageDirection();"/>
#ifdef MOZ_DEVTOOLS
<menuseparator id="inspect-separator" hidden="true"/>
<menuitem id="context-inspect"
hidden="true"
label="&inspectContextMenu.label;"
accesskey="&inspectContextMenu.accesskey;"
oncommand="gContextMenu.inspectNode();"/>
#endif

View file

@ -0,0 +1,19 @@
<!DOCTYPE window [
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
%brandDTD;
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd" >
%browserDTD;
<!ENTITY % baseMenuDTD SYSTEM "chrome://browser/locale/baseMenuOverlay.dtd" >
%baseMenuDTD;
<!ENTITY % charsetDTD SYSTEM "chrome://browser/locale/charsetMenu.dtd" >
%charsetDTD;
<!ENTITY % textcontextDTD SYSTEM "chrome://global/locale/textcontext.dtd" >
%textcontextDTD;
<!ENTITY % customizeToolbarDTD SYSTEM "chrome://global/locale/customizeToolbar.dtd">
%customizeToolbarDTD;
<!ENTITY % placesDTD SYSTEM "chrome://browser/locale/places/places.dtd">
%placesDTD;
<!ENTITY % aboutHomeDTD SYSTEM "chrome://browser/locale/aboutHome.dtd">
%aboutHomeDTD;
]>

View file

@ -0,0 +1,224 @@
# -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# 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/.
/**
* The Feed Handler object manages discovery of RSS/ATOM feeds in web pages
* and shows UI when they are discovered.
*/
var FeedHandler = {
/* Pale Moon: Address Bar: Feeds
* The click handler for the Feed icon in the location bar. Opens the
* subscription page if user is not given a choice of feeds.
* (Otherwise the list of available feeds will be presented to the
* user in a popup menu.)
*/
onFeedButtonPMClick: function(event) {
event.stopPropagation();
if (event.target.hasAttribute("feed") &&
event.eventPhase == Event.AT_TARGET &&
(event.button == 0 || event.button == 1)) {
this.subscribeToFeed(null, event);
}
},
/**
* The click handler for the Feed icon in the toolbar. Opens the
* subscription page if user is not given a choice of feeds.
* (Otherwise the list of available feeds will be presented to the
* user in a popup menu.)
*/
onFeedButtonClick: function(event) {
event.stopPropagation();
let feeds = gBrowser.selectedBrowser.feeds || [];
// If there are multiple feeds, the menu will open, so no need to do
// anything. If there are no feeds, nothing to do either.
if (feeds.length != 1)
return;
if (event.eventPhase == Event.AT_TARGET &&
(event.button == 0 || event.button == 1)) {
this.subscribeToFeed(feeds[0].href, event);
}
},
/** Called when the user clicks on the Subscribe to This Page... menu item.
* Builds a menu of unique feeds associated with the page, and if there
* is only one, shows the feed inline in the browser window.
* @param menuPopup
* The feed list menupopup to be populated.
* @returns true if the menu should be shown, false if there was only
* one feed and the feed should be shown inline in the browser
* window (do not show the menupopup).
*/
buildFeedList: function(menuPopup) {
var feeds = gBrowser.selectedBrowser.feeds;
if (feeds == null) {
// XXX hack -- menu opening depends on setting of an "open"
// attribute, and the menu refuses to open if that attribute is
// set (because it thinks it's already open). onpopupshowing gets
// called after the attribute is unset, and it doesn't get unset
// if we return false. so we unset it here; otherwise, the menu
// refuses to work past this point.
menuPopup.parentNode.removeAttribute("open");
return false;
}
while (menuPopup.firstChild)
menuPopup.removeChild(menuPopup.firstChild);
if (feeds.length == 1) {
var feedButtonPM = document.getElementById("ub-feed-button");
if (feedButtonPM)
feedButtonPM.setAttribute("feed", feeds[0].href);
return false;
}
if (feeds.length <= 1)
return false;
// Build the menu showing the available feed choices for viewing.
for (let feedInfo of feeds) {
var menuItem = document.createElement("menuitem");
var baseTitle = feedInfo.title || feedInfo.href;
var labelStr = gNavigatorBundle.getFormattedString("feedShowFeedNew", [baseTitle]);
menuItem.setAttribute("class", "feed-menuitem");
menuItem.setAttribute("label", labelStr);
menuItem.setAttribute("feed", feedInfo.href);
menuItem.setAttribute("tooltiptext", feedInfo.href);
menuItem.setAttribute("crop", "center");
menuPopup.appendChild(menuItem);
}
return true;
},
/**
* Subscribe to a given feed. Called when
* 1. Page has a single feed and user clicks feed icon in location bar
* 2. Page has a single feed and user selects Subscribe menu item
* 3. Page has multiple feeds and user selects from feed icon popup
* 4. Page has multiple feeds and user selects from Subscribe submenu
* @param href
* The feed to subscribe to. May be null, in which case the
* event target's feed attribute is examined.
* @param event
* The event this method is handling. Used to decide where
* to open the preview UI. (Optional, unless href is null)
*/
subscribeToFeed: function(href, event) {
// Just load the feed in the content area to either subscribe or show the
// preview UI
if (!href)
href = event.target.getAttribute("feed");
urlSecurityCheck(href, gBrowser.contentPrincipal,
Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
var feedURI = makeURI(href, document.characterSet);
// Use the feed scheme so X-Moz-Is-Feed will be set
// The value doesn't matter
if (/^https?$/.test(feedURI.scheme))
href = "feed:" + href;
this.loadFeed(href, event);
},
loadFeed: function(href, event) {
var feeds = gBrowser.selectedBrowser.feeds;
try {
openUILink(href, event, { ignoreAlt: true });
}
finally {
// We might default to a livebookmarks modal dialog,
// so reset that if the user happens to click it again
gBrowser.selectedBrowser.feeds = feeds;
}
},
get _feedMenuitem() {
delete this._feedMenuitem;
return this._feedMenuitem = document.getElementById("singleFeedMenuitemState");
},
get _feedMenupopup() {
delete this._feedMenupopup;
return this._feedMenupopup = document.getElementById("multipleFeedsMenuState");
},
/**
* Update the browser UI to show whether or not feeds are available when
* a page is loaded or the user switches tabs to a page that has feeds.
*/
updateFeeds: function() {
if (this._updateFeedTimeout)
clearTimeout(this._updateFeedTimeout);
var feeds = gBrowser.selectedBrowser.feeds;
var haveFeeds = feeds && feeds.length > 0;
var feedButtonPM = document.getElementById("ub-feed-button");
var feedButton = document.getElementById("feed-button");
if (feedButton)
feedButton.disabled = !haveFeeds;
if (feedButtonPM) {
if (!haveFeeds) {
feedButtonPM.collapsed = true;
feedButtonPM.removeAttribute("feed");
} else {
feedButtonPM.collapsed = !gPrefService.getBoolPref("browser.urlbar.rss");
}
}
if (!haveFeeds) {
this._feedMenuitem.setAttribute("disabled", "true");
this._feedMenuitem.removeAttribute("hidden");
this._feedMenupopup.setAttribute("hidden", "true");
return;
}
if (feeds.length > 1) {
if (feedButtonPM)
feedButtonPM.removeAttribute("feed");
this._feedMenuitem.setAttribute("hidden", "true");
this._feedMenupopup.removeAttribute("hidden");
} else {
if (feedButtonPM)
feedButtonPM.setAttribute("feed", feeds[0].href);
this._feedMenuitem.setAttribute("feed", feeds[0].href);
this._feedMenuitem.removeAttribute("disabled");
this._feedMenuitem.removeAttribute("hidden");
this._feedMenupopup.setAttribute("hidden", "true");
}
},
addFeed: function(link, targetDoc) {
// find which tab this is for, and set the attribute on the browser
var browserForLink = gBrowser.getBrowserForDocument(targetDoc);
if (!browserForLink) {
// ignore feeds loaded in subframes (see bug 305472)
return;
}
if (!browserForLink.feeds)
browserForLink.feeds = [];
browserForLink.feeds.push({ href: link.href, title: link.title });
// If this addition was for the current browser, update the UI. For
// background browsers, we'll update on tab switch.
if (browserForLink == gBrowser.selectedBrowser) {
var feedButtonPM = document.getElementById("ub-feed-button");
if (feedButtonPM)
feedButtonPM.collapsed = !gPrefService.getBoolPref("browser.urlbar.rss");
// Batch updates to avoid updating the UI for multiple onLinkAdded events
// fired within 100ms of each other.
if (this._updateFeedTimeout)
clearTimeout(this._updateFeedTimeout);
this._updateFeedTimeout = setTimeout(this.updateFeeds.bind(this), 100);
}
}
};

View file

@ -0,0 +1,607 @@
# -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# 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/.
var FullScreen = {
_XULNS: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
get _fullScrToggler() {
delete this._fullScrToggler;
return this._fullScrToggler = document.getElementById("fullscr-toggler");
},
toggle: function (event) {
var enterFS = window.fullScreen;
// We get the fullscreen event _before_ the window transitions into or out of FS mode.
if (event && event.type == "fullscreen")
enterFS = !enterFS;
// Toggle the View:FullScreen command, which controls elements like the
// fullscreen menuitem, menubars, and the appmenu.
let fullscreenCommand = document.getElementById("View:FullScreen");
if (enterFS) {
fullscreenCommand.setAttribute("checked", enterFS);
} else {
fullscreenCommand.removeAttribute("checked");
}
#ifdef XP_MACOSX
// Make sure the menu items are adjusted.
document.getElementById("enterFullScreenItem").hidden = enterFS;
document.getElementById("exitFullScreenItem").hidden = !enterFS;
#endif
// On OS X Lion we don't want to hide toolbars when entering fullscreen, unless
// we're entering DOM fullscreen, in which case we should hide the toolbars.
// If we're leaving fullscreen, then we'll go through the exit code below to
// make sure toolbars are made visible in the case of DOM fullscreen.
if (enterFS && this.useLionFullScreen) {
if (document.mozFullScreen) {
this.showXULChrome("toolbar", false);
}
else {
gNavToolbox.setAttribute("inFullscreen", true);
document.documentElement.setAttribute("inFullscreen", true);
}
return;
}
// show/hide menubars, toolbars (except the full screen toolbar)
this.showXULChrome("toolbar", !enterFS);
if (enterFS) {
// Add a tiny toolbar to receive mouseover and dragenter events, and provide affordance.
// This will help simulate the "collapse" metaphor while also requiring less code and
// events than raw listening of mouse coords. We don't add the toolbar in DOM full-screen
// mode, only browser full-screen mode.
if (!document.mozFullScreen) {
this._fullScrToggler.addEventListener("mouseover", this._expandCallback, false);
this._fullScrToggler.addEventListener("dragenter", this._expandCallback, false);
}
if (gPrefService.getBoolPref("browser.fullscreen.autohide"))
gBrowser.mPanelContainer.addEventListener("mousemove",
this._collapseCallback, false);
document.addEventListener("keypress", this._keyToggleCallback, false);
document.addEventListener("popupshown", this._setPopupOpen, false);
document.addEventListener("popuphidden", this._setPopupOpen, false);
// We don't animate the toolbar collapse if in DOM full-screen mode,
// as the size of the content area would still be changing after the
// mozfullscreenchange event fired, which could confuse content script.
this._shouldAnimate = !document.mozFullScreen;
this.mouseoverToggle(false);
// Autohide prefs
gPrefService.addObserver("browser.fullscreen", this, false);
}
else {
// The user may quit fullscreen during an animation
this._cancelAnimation();
gNavToolbox.style.marginTop = "";
if (this._isChromeCollapsed)
this.mouseoverToggle(true);
// This is needed if they use the context menu to quit fullscreen
this._isPopupOpen = false;
document.documentElement.removeAttribute("inDOMFullscreen");
this.cleanup();
}
},
exitDomFullScreen : function() {
document.mozCancelFullScreen();
},
handleEvent: function (event) {
switch (event.type) {
case "activate":
if (document.mozFullScreen) {
this.showWarning(this.fullscreenDoc);
}
break;
case "transitionend":
if (event.propertyName == "opacity")
this.cancelWarning();
break;
}
},
enterDomFullscreen : function(event) {
if (!document.mozFullScreen)
return;
// However, if we receive a "MozEnteredDomFullScreen" event for a document
// which is not a subdocument of a currently active (ie. visible) browser
// or iframe, we know that we've switched to a different frame since the
// request to enter full-screen was made, so we should exit full-screen
// since the "full-screen document" isn't acutally visible.
if (!event.target.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell).isActive) {
document.mozCancelFullScreen();
return;
}
let focusManager = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
if (focusManager.activeWindow != window) {
// The top-level window has lost focus since the request to enter
// full-screen was made. Cancel full-screen.
document.mozCancelFullScreen();
return;
}
document.documentElement.setAttribute("inDOMFullscreen", true);
if (gFindBarInitialized)
gFindBar.close();
this.showWarning(event.target);
// Exit DOM full-screen mode upon open, close, or change tab.
gBrowser.tabContainer.addEventListener("TabOpen", this.exitDomFullScreen);
gBrowser.tabContainer.addEventListener("TabClose", this.exitDomFullScreen);
gBrowser.tabContainer.addEventListener("TabSelect", this.exitDomFullScreen);
// Add listener to detect when the fullscreen window is re-focused.
// If a fullscreen window loses focus, we show a warning when the
// fullscreen window is refocused.
if (!this.useLionFullScreen) {
window.addEventListener("activate", this);
}
// Cancel any "hide the toolbar" animation which is in progress, and make
// the toolbar hide immediately.
this._cancelAnimation();
this.mouseoverToggle(false);
// Remove listeners on the full-screen toggler, so that mouseover
// the top of the screen will not cause the toolbar to re-appear.
this._fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
this._fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
},
cleanup: function () {
if (window.fullScreen) {
gBrowser.mPanelContainer.removeEventListener("mousemove",
this._collapseCallback, false);
document.removeEventListener("keypress", this._keyToggleCallback, false);
document.removeEventListener("popupshown", this._setPopupOpen, false);
document.removeEventListener("popuphidden", this._setPopupOpen, false);
gPrefService.removeObserver("browser.fullscreen", this);
this._fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
this._fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
this.cancelWarning();
gBrowser.tabContainer.removeEventListener("TabOpen", this.exitDomFullScreen);
gBrowser.tabContainer.removeEventListener("TabClose", this.exitDomFullScreen);
gBrowser.tabContainer.removeEventListener("TabSelect", this.exitDomFullScreen);
if (!this.useLionFullScreen)
window.removeEventListener("activate", this);
this.fullscreenDoc = null;
}
},
observe: function(aSubject, aTopic, aData)
{
if (aData == "browser.fullscreen.autohide") {
if (gPrefService.getBoolPref("browser.fullscreen.autohide")) {
gBrowser.mPanelContainer.addEventListener("mousemove",
this._collapseCallback, false);
}
else {
gBrowser.mPanelContainer.removeEventListener("mousemove",
this._collapseCallback, false);
}
}
},
// Event callbacks
_expandCallback: function()
{
FullScreen.mouseoverToggle(true);
},
_collapseCallback: function()
{
FullScreen.mouseoverToggle(false);
},
_keyToggleCallback: function(aEvent)
{
// if we can use the keyboard (eg Ctrl+L or Ctrl+E) to open the toolbars, we
// should provide a way to collapse them too.
if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) {
FullScreen._shouldAnimate = false;
FullScreen.mouseoverToggle(false, true);
}
// F6 is another shortcut to the address bar, but its not covered in OpenLocation()
else if (aEvent.keyCode == aEvent.DOM_VK_F6)
FullScreen.mouseoverToggle(true);
},
// Checks whether we are allowed to collapse the chrome
_isPopupOpen: false,
_isChromeCollapsed: false,
_safeToCollapse: function(forceHide)
{
if (!gPrefService.getBoolPref("browser.fullscreen.autohide"))
return false;
// a popup menu is open in chrome: don't collapse chrome
if (!forceHide && this._isPopupOpen)
return false;
// a textbox in chrome is focused (location bar anyone?): don't collapse chrome
if (document.commandDispatcher.focusedElement &&
document.commandDispatcher.focusedElement.ownerDocument == document &&
document.commandDispatcher.focusedElement.localName == "input") {
if (forceHide)
// hidden textboxes that still have focus are bad bad bad
document.commandDispatcher.focusedElement.blur();
else
return false;
}
return true;
},
_setPopupOpen: function(aEvent)
{
// Popups should only veto chrome collapsing if they were opened when the chrome was not collapsed.
// Otherwise, they would not affect chrome and the user would expect the chrome to go away.
// e.g. we wouldn't want the autoscroll icon firing this event, so when the user
// toggles chrome when moving mouse to the top, it doesn't go away again.
if (aEvent.type == "popupshown" && !FullScreen._isChromeCollapsed &&
aEvent.target.localName != "tooltip" && aEvent.target.localName != "window")
FullScreen._isPopupOpen = true;
else if (aEvent.type == "popuphidden" && aEvent.target.localName != "tooltip" &&
aEvent.target.localName != "window")
FullScreen._isPopupOpen = false;
},
// Autohide helpers for the context menu item
getAutohide: function(aItem)
{
aItem.setAttribute("checked", gPrefService.getBoolPref("browser.fullscreen.autohide"));
},
setAutohide: function()
{
gPrefService.setBoolPref("browser.fullscreen.autohide", !gPrefService.getBoolPref("browser.fullscreen.autohide"));
},
// Animate the toolbars disappearing
_shouldAnimate: true,
_isAnimating: false,
_animationTimeout: 0,
_animationHandle: 0,
_animateUp: function() {
// check again, the user may have done something before the animation was due to start
if (!window.fullScreen || !this._safeToCollapse(false)) {
this._isAnimating = false;
this._shouldAnimate = true;
return;
}
this._animateStartTime = window.mozAnimationStartTime;
if (!this._animationHandle)
this._animationHandle = window.mozRequestAnimationFrame(this);
},
sample: function (timeStamp) {
const duration = 1500;
const timePassed = timeStamp - this._animateStartTime;
const pos = timePassed >= duration ? 1 :
1 - Math.pow(1 - timePassed / duration, 4);
if (pos >= 1) {
// We've animated enough
this._cancelAnimation();
gNavToolbox.style.marginTop = "";
this.mouseoverToggle(false);
return;
}
gNavToolbox.style.marginTop = (gNavToolbox.boxObject.height * pos * -1) + "px";
this._animationHandle = window.mozRequestAnimationFrame(this);
},
_cancelAnimation: function() {
window.mozCancelAnimationFrame(this._animationHandle);
this._animationHandle = 0;
clearTimeout(this._animationTimeout);
this._isAnimating = false;
this._shouldAnimate = false;
},
cancelWarning: function(event) {
if (!this.warningBox)
return;
this.warningBox.removeEventListener("transitionend", this);
if (this.warningFadeOutTimeout) {
clearTimeout(this.warningFadeOutTimeout);
this.warningFadeOutTimeout = null;
}
// Ensure focus switches away from the (now hidden) warning box. If the user
// clicked buttons in the fullscreen key authorization UI, it would have been
// focused, and any key events would be directed at the (now hidden) chrome
// document instead of the target document.
gBrowser.selectedBrowser.focus();
this.warningBox.setAttribute("hidden", true);
this.warningBox.removeAttribute("fade-warning-out");
this.warningBox.removeAttribute("obscure-browser");
this.warningBox = null;
},
setFullscreenAllowed: function(isApproved) {
// The "remember decision" checkbox is hidden when showing for documents that
// the permission manager can't handle (documents with URIs without a host).
// We simply require those to be approved every time instead.
let rememberCheckbox = document.getElementById("full-screen-remember-decision");
let uri = this.fullscreenDoc.nodePrincipal.URI;
if (!rememberCheckbox.hidden) {
if (rememberCheckbox.checked)
Services.perms.add(uri,
"fullscreen",
isApproved ? Services.perms.ALLOW_ACTION : Services.perms.DENY_ACTION,
Services.perms.EXPIRE_NEVER);
else if (isApproved) {
// The user has only temporarily approved fullscren for this fullscreen
// session only. Add the permission (so Goanna knows to approve any further
// fullscreen requests for this host in this fullscreen session) but add
// a listener to revoke the permission when the chrome document exits
// fullscreen.
Services.perms.add(uri,
"fullscreen",
Services.perms.ALLOW_ACTION,
Services.perms.EXPIRE_SESSION);
let host = uri.host;
var onFullscreenchange = function onFullscreenchange(event) {
if (event.target == document && document.mozFullScreenElement == null) {
// The chrome document has left fullscreen. Remove the temporary permission grant.
Services.perms.remove(host, "fullscreen");
document.removeEventListener("mozfullscreenchange", onFullscreenchange);
}
}
document.addEventListener("mozfullscreenchange", onFullscreenchange);
}
}
if (this.warningBox)
this.warningBox.setAttribute("fade-warning-out", "true");
// If the document has been granted fullscreen, notify Goanna so it can resume
// any pending pointer lock requests, otherwise exit fullscreen; the user denied
// the fullscreen request.
if (isApproved)
Services.obs.notifyObservers(this.fullscreenDoc, "fullscreen-approved", "");
else
document.mozCancelFullScreen();
},
warningBox: null,
warningFadeOutTimeout: null,
fullscreenDoc: null,
// Shows the fullscreen approval UI, or if the domain has already been approved
// for fullscreen, shows a warning that the site has entered fullscreen for a short
// duration.
showWarning: function(targetDoc) {
if (!document.mozFullScreen ||
!gPrefService.getBoolPref("full-screen-api.approval-required"))
return;
// Set the strings on the fullscreen approval UI.
this.fullscreenDoc = targetDoc;
let uri = this.fullscreenDoc.nodePrincipal.URI;
let host = null;
try {
host = uri.host;
} catch (e) { }
let hostLabel = document.getElementById("full-screen-domain-text");
let rememberCheckbox = document.getElementById("full-screen-remember-decision");
let isApproved = false;
if (host) {
// Document's principal's URI has a host. Display a warning including the hostname and
// show UI to enable the user to permanently grant this host permission to enter fullscreen.
let utils = {};
Cu.import("resource://gre/modules/DownloadUtils.jsm", utils);
let displayHost = utils.DownloadUtils.getURIHost(uri.spec)[0];
let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
hostLabel.textContent = bundle.formatStringFromName("fullscreen.entered", [displayHost], 1);
hostLabel.removeAttribute("hidden");
rememberCheckbox.label = bundle.formatStringFromName("fullscreen.rememberDecision", [displayHost], 1);
rememberCheckbox.checked = false;
rememberCheckbox.removeAttribute("hidden");
// Note we only allow documents whose principal's URI has a host to
// store permission grants.
isApproved = Services.perms.testPermission(uri, "fullscreen") == Services.perms.ALLOW_ACTION;
} else {
hostLabel.setAttribute("hidden", "true");
rememberCheckbox.setAttribute("hidden", "true");
}
// Note: the warning box can be non-null if the warning box from the previous request
// wasn't hidden before another request was made.
if (!this.warningBox) {
this.warningBox = document.getElementById("full-screen-warning-container");
// Add a listener to clean up state after the warning is hidden.
this.warningBox.addEventListener("transitionend", this);
this.warningBox.removeAttribute("hidden");
} else {
if (this.warningFadeOutTimeout) {
clearTimeout(this.warningFadeOutTimeout);
this.warningFadeOutTimeout = null;
}
this.warningBox.removeAttribute("fade-warning-out");
}
// If fullscreen mode has not yet been approved for the fullscreen
// document's domain, show the approval UI and don't auto fade out the
// fullscreen warning box. Otherwise, we're just notifying of entry into
// fullscreen mode. Note if the resource's host is null, we must be
// showing a local file or a local data URI, and we require explicit
// approval every time.
let authUI = document.getElementById("full-screen-approval-pane");
if (isApproved) {
authUI.setAttribute("hidden", "true");
this.warningBox.removeAttribute("obscure-browser");
} else {
// Partially obscure the <browser> element underneath the approval UI.
this.warningBox.setAttribute("obscure-browser", "true");
authUI.removeAttribute("hidden");
}
// If we're not showing the fullscreen approval UI, we're just notifying the user
// of the transition, so set a timeout to fade the warning out after a few moments.
if (isApproved)
this.warningFadeOutTimeout =
setTimeout(
function() {
if (this.warningBox)
this.warningBox.setAttribute("fade-warning-out", "true");
}.bind(this),
3000);
},
mouseoverToggle: function(aShow, forceHide)
{
// Don't do anything if:
// a) we're already in the state we want,
// b) we're animating and will become collapsed soon, or
// c) we can't collapse because it would be undesirable right now
if (aShow != this._isChromeCollapsed || (!aShow && this._isAnimating) ||
(!aShow && !this._safeToCollapse(forceHide)))
return;
// browser.fullscreen.animateUp
// 0 - never animate up
// 1 - animate only for first collapse after entering fullscreen (default for perf's sake)
// 2 - animate every time it collapses
if (gPrefService.getIntPref("browser.fullscreen.animateUp") == 0)
this._shouldAnimate = false;
if (!aShow && this._shouldAnimate) {
this._isAnimating = true;
this._shouldAnimate = false;
this._animationTimeout = setTimeout(this._animateUp.bind(this), 800);
return;
}
// The chrome is collapsed so don't spam needless mousemove events
if (aShow) {
gBrowser.mPanelContainer.addEventListener("mousemove",
this._collapseCallback, false);
}
else {
gBrowser.mPanelContainer.removeEventListener("mousemove",
this._collapseCallback, false);
}
// Hiding/collapsing the toolbox interferes with the tab bar's scrollbox,
// so we just move it off-screen instead. See bug 430687.
gNavToolbox.style.marginTop =
aShow ? "" : -gNavToolbox.getBoundingClientRect().height + "px";
this._fullScrToggler.collapsed = aShow;
this._isChromeCollapsed = !aShow;
if (gPrefService.getIntPref("browser.fullscreen.animateUp") == 2)
this._shouldAnimate = true;
},
showXULChrome: function(aTag, aShow)
{
var els = document.getElementsByTagNameNS(this._XULNS, aTag);
for (let el of els) {
// XXX don't interfere with previously collapsed toolbars
if (el.getAttribute("fullscreentoolbar") == "true") {
if (!aShow) {
var toolbarMode = el.getAttribute("mode");
if (toolbarMode != "text") {
el.setAttribute("saved-mode", toolbarMode);
el.setAttribute("saved-iconsize", el.getAttribute("iconsize"));
el.setAttribute("mode", "icons");
el.setAttribute("iconsize", "small");
}
// Give the main nav bar and the tab bar the fullscreen context menu,
// otherwise remove context menu to prevent breakage
el.setAttribute("saved-context", el.getAttribute("context"));
if (el.id == "nav-bar" || el.id == "TabsToolbar")
el.setAttribute("context", "autohide-context");
else
el.removeAttribute("context");
// Set the inFullscreen attribute to allow specific styling
// in fullscreen mode
el.setAttribute("inFullscreen", true);
}
else {
var restoreAttr = function restoreAttr(attrName) {
var savedAttr = "saved-" + attrName;
if (el.hasAttribute(savedAttr)) {
el.setAttribute(attrName, el.getAttribute(savedAttr));
el.removeAttribute(savedAttr);
}
}
restoreAttr("mode");
restoreAttr("iconsize");
restoreAttr("context");
el.removeAttribute("inFullscreen");
}
} else {
// use moz-collapsed so it doesn't persist hidden/collapsed,
// so that new windows don't have missing toolbars
if (aShow)
el.removeAttribute("moz-collapsed");
else
el.setAttribute("moz-collapsed", "true");
}
}
if (aShow) {
gNavToolbox.removeAttribute("inFullscreen");
document.documentElement.removeAttribute("inFullscreen");
} else {
gNavToolbox.setAttribute("inFullscreen", true);
document.documentElement.setAttribute("inFullscreen", true);
}
// In tabs-on-top mode, move window controls to the tab bar,
// and in tabs-on-bottom mode, move them back to the navigation toolbar.
// When there is a chance the tab bar may be collapsed, put window
// controls on nav bar.
var fullscreenctls = document.getElementById("window-controls");
var navbar = document.getElementById("nav-bar");
var ctlsOnTabbar = window.toolbar.visible &&
(navbar.collapsed || (TabsOnTop.enabled &&
!gPrefService.getBoolPref("browser.tabs.autoHide")));
if (fullscreenctls.parentNode == navbar && ctlsOnTabbar) {
fullscreenctls.removeAttribute("flex");
document.getElementById("TabsToolbar").appendChild(fullscreenctls);
}
else if (fullscreenctls.parentNode.id == "TabsToolbar" && !ctlsOnTabbar) {
fullscreenctls.setAttribute("flex", "1");
navbar.appendChild(fullscreenctls);
}
fullscreenctls.hidden = aShow;
ToolbarIconColor.inferFromText();
}
};
XPCOMUtils.defineLazyGetter(FullScreen, "useLionFullScreen", function() {
// We'll only use OS X Lion full screen if we're
// * on OS X
// * on Lion or higher (Darwin 11+)
// * have fullscreenbutton="true"
#ifdef XP_MACOSX
return parseFloat(Services.sysinfo.getProperty("version")) >= 11 &&
document.documentElement.getAttribute("fullscreenbutton") == "true";
#else
return false;
#endif
});

View file

@ -0,0 +1,550 @@
/*
#ifdef 0
* 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/.
#endif
*/
// One of the possible values for the mousewheel.* preferences.
// From nsEventStateManager.cpp.
const MOUSE_SCROLL_ZOOM = 3;
/**
* Controls the "full zoom" setting and its site-specific preferences.
*/
var FullZoom = {
// Identifies the setting in the content prefs database.
name: "browser.content.full-zoom",
// browser.zoom.siteSpecific preference cache
_siteSpecificPref: undefined,
// browser.zoom.updateBackgroundTabs preference cache
updateBackgroundTabs: undefined,
// This maps the browser to monotonically increasing integer
// tokens. _browserTokenMap[browser] is increased each time the zoom is
// changed in the browser. See _getBrowserToken and _ignorePendingZoomAccesses.
_browserTokenMap: new WeakMap(),
// Stores initial locations if we receive onLocationChange
// events before we're initialized.
_initialLocations: new WeakMap(),
get siteSpecific() {
return this._siteSpecificPref;
},
//**************************************************************************//
// nsISupports
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMEventListener,
Ci.nsIObserver,
Ci.nsIContentPrefObserver,
Ci.nsISupportsWeakReference,
Ci.nsISupports]),
//**************************************************************************//
// Initialization & Destruction
init: function FullZoom_init() {
// Listen for scrollwheel events so we can save scrollwheel-based changes.
window.addEventListener("DOMMouseScroll", this, false);
// Register ourselves with the service so we know when our pref changes.
this._cps2 = Cc["@mozilla.org/content-pref/service;1"].
getService(Ci.nsIContentPrefService2);
this._cps2.addObserverForName(this.name, this);
this._siteSpecificPref =
gPrefService.getBoolPref("browser.zoom.siteSpecific");
this.updateBackgroundTabs =
gPrefService.getBoolPref("browser.zoom.updateBackgroundTabs");
// Listen for changes to the browser.zoom branch so we can enable/disable
// updating background tabs and per-site saving and restoring of zoom levels.
gPrefService.addObserver("browser.zoom.", this, true);
// If we received onLocationChange events for any of the current browsers
// before we were initialized we want to replay those upon initialization.
for (let browser of gBrowser.browsers) {
if (this._initialLocations.has(browser)) {
this.onLocationChange(...this._initialLocations.get(browser), browser);
}
}
// This should be nulled after initialization.
this._initialLocations.clear();
this._initialLocations = null;
},
destroy: function FullZoom_destroy() {
gPrefService.removeObserver("browser.zoom.", this);
this._cps2.removeObserverForName(this.name, this);
window.removeEventListener("DOMMouseScroll", this, false);
},
//**************************************************************************//
// Event Handlers
// nsIDOMEventListener
handleEvent: function FullZoom_handleEvent(event) {
switch (event.type) {
case "DOMMouseScroll":
this._handleMouseScrolled(event);
break;
}
},
_handleMouseScrolled: function FullZoom__handleMouseScrolled(event) {
// Construct the "mousewheel action" pref key corresponding to this event.
// Based on nsEventStateManager::WheelPrefs::GetBasePrefName().
var pref = "mousewheel.";
var pressedModifierCount = event.shiftKey + event.ctrlKey + event.altKey +
event.metaKey + event.getModifierState("OS");
if (pressedModifierCount != 1) {
pref += "default.";
} else if (event.shiftKey) {
pref += "with_shift.";
} else if (event.ctrlKey) {
pref += "with_control.";
} else if (event.altKey) {
pref += "with_alt.";
} else if (event.metaKey) {
pref += "with_meta.";
} else {
pref += "with_win.";
}
pref += "action";
// Don't do anything if this isn't a "zoom" scroll event.
var isZoomEvent = false;
try {
isZoomEvent = (gPrefService.getIntPref(pref) == MOUSE_SCROLL_ZOOM);
} catch (e) {}
if (!isZoomEvent)
return;
// XXX Lazily cache all the possible action prefs so we don't have to get
// them anew from the pref service for every scroll event? We'd have to
// make sure to observe them so we can update the cache when they change.
// We have to call _applyZoomToPref in a timeout because we handle the
// event before the event state manager has a chance to apply the zoom
// during nsEventStateManager::PostHandleEvent.
let browser = gBrowser.selectedBrowser;
let token = this._getBrowserToken(browser);
window.setTimeout(function () {
if (token.isCurrent)
this._applyZoomToPref(browser);
}.bind(this), 0);
},
// nsIObserver
observe: function (aSubject, aTopic, aData) {
switch (aTopic) {
case "nsPref:changed":
switch (aData) {
case "browser.zoom.siteSpecific":
this._siteSpecificPref =
gPrefService.getBoolPref("browser.zoom.siteSpecific");
break;
case "browser.zoom.updateBackgroundTabs":
this.updateBackgroundTabs =
gPrefService.getBoolPref("browser.zoom.updateBackgroundTabs");
break;
}
break;
}
},
// nsIContentPrefObserver
onContentPrefSet: function FullZoom_onContentPrefSet(aGroup, aName, aValue) {
this._onContentPrefChanged(aGroup, aValue);
},
onContentPrefRemoved: function FullZoom_onContentPrefRemoved(aGroup, aName) {
this._onContentPrefChanged(aGroup, undefined);
},
/**
* Appropriately updates the zoom level after a content preference has
* changed.
*
* @param aGroup The group of the changed preference.
* @param aValue The new value of the changed preference. Pass undefined to
* indicate the preference's removal.
*/
_onContentPrefChanged: function FullZoom__onContentPrefChanged(aGroup, aValue) {
if (this._isNextContentPrefChangeInternal) {
// Ignore changes that FullZoom itself makes. This works because the
// content pref service calls callbacks before notifying observers, and it
// does both in the same turn of the event loop.
delete this._isNextContentPrefChangeInternal;
return;
}
let browser = gBrowser.selectedBrowser;
if (!browser.currentURI)
return;
let domain = this._cps2.extractDomain(browser.currentURI.spec);
if (aGroup) {
if (aGroup == domain)
this._applyPrefToZoom(aValue, browser);
return;
}
this._globalValue = aValue === undefined ? aValue :
this._ensureValid(aValue);
// If the current page doesn't have a site-specific preference, then its
// zoom should be set to the new global preference now that the global
// preference has changed.
let hasPref = false;
let ctxt = this._loadContextFromBrowser(browser);
let token = this._getBrowserToken(browser);
this._cps2.getByDomainAndName(browser.currentURI.spec, this.name, ctxt, {
handleResult: function () hasPref = true,
handleCompletion: function () {
if (!hasPref && token.isCurrent)
this._applyPrefToZoom(undefined, browser);
}.bind(this)
});
},
// location change observer
/**
* Called when the location of a tab changes.
* When that happens, we need to update the current zoom level if appropriate.
*
* @param aURI
* A URI object representing the new location.
* @param aIsTabSwitch
* Whether this location change has happened because of a tab switch.
* @param aBrowser
* (optional) browser object displaying the document
*/
onLocationChange: function FullZoom_onLocationChange(aURI, aIsTabSwitch, aBrowser) {
let browser = aBrowser || gBrowser.selectedBrowser;
// If we haven't been initialized yet but receive an onLocationChange
// notification then let's store and replay it upon initialization.
if (this._initialLocations) {
this._initialLocations.set(browser, [aURI, aIsTabSwitch]);
return;
}
// Ignore all pending async zoom accesses in the browser. Pending accesses
// that started before the location change will be prevented from applying
// to the new location.
this._ignorePendingZoomAccesses(browser);
if (!aURI || (aIsTabSwitch && !this.siteSpecific)) {
this._notifyOnLocationChange();
return;
}
// Avoid the cps roundtrip and apply the default/global pref.
if (aURI.spec == "about:blank") {
this._applyPrefToZoom(undefined, browser,
this._notifyOnLocationChange.bind(this));
return;
}
// Media documents should always start at 1, and are not affected by prefs.
if (!aIsTabSwitch && browser.isSyntheticDocument) {
ZoomManager.setZoomForBrowser(browser, 1);
// _ignorePendingZoomAccesses already called above, so no need here.
this._notifyOnLocationChange();
return;
}
// See if the zoom pref is cached.
let ctxt = this._loadContextFromBrowser(browser);
let pref = this._cps2.getCachedByDomainAndName(aURI.spec, this.name, ctxt);
if (pref) {
this._applyPrefToZoom(pref.value, browser,
this._notifyOnLocationChange.bind(this));
return;
}
// It's not cached, so we have to asynchronously fetch it.
let value = undefined;
let token = this._getBrowserToken(browser);
this._cps2.getByDomainAndName(aURI.spec, this.name, ctxt, {
handleResult: function (resultPref) value = resultPref.value,
handleCompletion: function () {
if (!token.isCurrent) {
this._notifyOnLocationChange();
return;
}
this._applyPrefToZoom(value, browser,
this._notifyOnLocationChange.bind(this));
}.bind(this)
});
},
// update state of zoom type menu item
updateMenu: function FullZoom_updateMenu() {
var menuItem = document.getElementById("toggle_zoom");
menuItem.setAttribute("checked", !ZoomManager.useFullZoom);
},
//**************************************************************************//
// Setting & Pref Manipulation
/**
* Reduces the zoom level of the page in the current browser.
*/
reduce: function FullZoom_reduce() {
ZoomManager.reduce();
let browser = gBrowser.selectedBrowser;
this._ignorePendingZoomAccesses(browser);
this._applyZoomToPref(browser);
},
/**
* Enlarges the zoom level of the page in the current browser.
*/
enlarge: function FullZoom_enlarge() {
ZoomManager.enlarge();
let browser = gBrowser.selectedBrowser;
this._ignorePendingZoomAccesses(browser);
this._applyZoomToPref(browser);
},
/**
* Sets the zoom level of the page in the current browser to the global zoom
* level.
*/
reset: function FullZoom_reset() {
let browser = gBrowser.selectedBrowser;
let token = this._getBrowserToken(browser);
this._getGlobalValue(browser, function (value) {
if (token.isCurrent) {
ZoomManager.setZoomForBrowser(browser, value === undefined ? 1 : value);
this._ignorePendingZoomAccesses(browser);
}
});
this._removePref(browser);
},
/**
* Set the zoom level for a given browser.
*
* Per nsPresContext::setFullZoom, we can set the zoom to its current value
* without significant impact on performance, as the setting is only applied
* if it differs from the current setting. In fact getting the zoom and then
* checking ourselves if it differs costs more.
*
* And perhaps we should always set the zoom even if it was more expensive,
* since nsDocumentViewer::SetTextZoom claims that child documents can have
* a different text zoom (although it would be unusual), and it implies that
* those child text zooms should get updated when the parent zoom gets set,
* and perhaps the same is true for full zoom
* (although nsDocumentViewer::SetFullZoom doesn't mention it).
*
* So when we apply new zoom values to the browser, we simply set the zoom.
* We don't check first to see if the new value is the same as the current
* one.
*
* @param aValue The zoom level value.
* @param aBrowser The zoom is set in this browser. Required.
* @param aCallback If given, it's asynchronously called when complete.
*/
_applyPrefToZoom: function FullZoom__applyPrefToZoom(aValue, aBrowser, aCallback) {
if (!this.siteSpecific || gInPrintPreviewMode) {
this._executeSoon(aCallback);
return;
}
// The browser is sometimes half-destroyed because this method is called
// by content pref service callbacks, which themselves can be called at any
// time, even after browsers are closed.
if (!aBrowser.parentNode || aBrowser.isSyntheticDocument) {
this._executeSoon(aCallback);
return;
}
if (aValue !== undefined) {
ZoomManager.setZoomForBrowser(aBrowser, this._ensureValid(aValue));
this._ignorePendingZoomAccesses(aBrowser);
this._executeSoon(aCallback);
return;
}
let token = this._getBrowserToken(aBrowser);
this._getGlobalValue(aBrowser, function (value) {
if (token.isCurrent) {
ZoomManager.setZoomForBrowser(aBrowser, value === undefined ? 1 : value);
this._ignorePendingZoomAccesses(aBrowser);
}
this._executeSoon(aCallback);
});
},
/**
* Saves the zoom level of the page in the given browser to the content
* prefs store.
*
* @param browser The zoom of this browser will be saved. Required.
*/
_applyZoomToPref: function FullZoom__applyZoomToPref(browser) {
if (!this.siteSpecific ||
gInPrintPreviewMode ||
browser.isSyntheticDocument)
return;
this._cps2.set(browser.currentURI.spec, this.name,
ZoomManager.getZoomForBrowser(browser),
this._loadContextFromBrowser(browser), {
handleCompletion: function () {
this._isNextContentPrefChangeInternal = true;
}.bind(this),
});
},
/**
* Removes from the content prefs store the zoom level of the given browser.
*
* @param browser The zoom of this browser will be removed. Required.
*/
_removePref: function FullZoom__removePref(browser) {
if (browser.isSyntheticDocument)
return;
let ctxt = this._loadContextFromBrowser(browser);
this._cps2.removeByDomainAndName(browser.currentURI.spec, this.name, ctxt, {
handleCompletion: function () {
this._isNextContentPrefChangeInternal = true;
}.bind(this),
});
},
//**************************************************************************//
// Utilities
/**
* Returns the zoom change token of the given browser. Asynchronous
* operations that access the given browser's zoom should use this method to
* capture the token before starting and use token.isCurrent to determine if
* it's safe to access the zoom when done. If token.isCurrent is false, then
* after the async operation started, either the browser's zoom was changed or
* the browser was destroyed, and depending on what the operation is doing, it
* may no longer be safe to set and get its zoom.
*
* @param browser The token of this browser will be returned.
* @return An object with an "isCurrent" getter.
*/
_getBrowserToken: function FullZoom__getBrowserToken(browser) {
let map = this._browserTokenMap;
if (!map.has(browser))
map.set(browser, 0);
return {
token: map.get(browser),
get isCurrent() {
// At this point, the browser may have been destructed and unbound but
// its outer ID not removed from the map because outer-window-destroyed
// hasn't been received yet. In that case, the browser is unusable, it
// has no properties, so return false. Check for this case by getting a
// property, say, docShell.
return map.get(browser) === this.token && browser.parentNode;
},
};
},
/**
* Increments the zoom change token for the given browser so that pending
* async operations know that it may be unsafe to access they zoom when they
* finish.
*
* @param browser Pending accesses in this browser will be ignored.
*/
_ignorePendingZoomAccesses: function FullZoom__ignorePendingZoomAccesses(browser) {
let map = this._browserTokenMap;
map.set(browser, (map.get(browser) || 0) + 1);
},
_ensureValid: function FullZoom__ensureValid(aValue) {
// Note that undefined is a valid value for aValue that indicates a known-
// not-to-exist value.
if (isNaN(aValue))
return 1;
if (aValue < ZoomManager.MIN)
return ZoomManager.MIN;
if (aValue > ZoomManager.MAX)
return ZoomManager.MAX;
return aValue;
},
/**
* Gets the global browser.content.full-zoom content preference.
*
* WARNING: callback may be called synchronously or asynchronously. The
* reason is that it's usually desirable to avoid turns of the event loop
* where possible, since they can lead to visible, jarring jumps in zoom
* level. It's not always possible to avoid them, though. As a convenience,
* then, this method takes a callback and returns nothing.
*
* @param browser The content browser pertaining to the zoom.
* @param callback Synchronously or asynchronously called when done. It's
* bound to this object (FullZoom) and called as:
* callback(prefValue)
*/
_getGlobalValue: function FullZoom__getGlobalValue(browser, callback) {
// * !("_globalValue" in this) => global value not yet cached.
// * this._globalValue === undefined => global value known not to exist.
// * Otherwise, this._globalValue is a number, the global value.
if ("_globalValue" in this) {
callback.call(this, this._globalValue, true);
return;
}
let value = undefined;
this._cps2.getGlobal(this.name, this._loadContextFromBrowser(browser), {
handleResult: function (pref) value = pref.value,
handleCompletion: function (reason) {
this._globalValue = this._ensureValid(value);
callback.call(this, this._globalValue);
}.bind(this)
});
},
/**
* Gets the load context from the given content browser.
*
* @param Browser The Browser whose load context will be returned.
* @return The nsILoadContext of the given Browser.
*/
_loadContextFromBrowser: function FullZoom__loadContextFromBrowser(browser) {
return browser.loadContext;
},
/**
* Asynchronously broadcasts a "browser-fullZoom:locationChange" notification
* so that tests can select tabs, load pages, etc. and be notified when the
* zoom levels on those pages change. The notification is always asynchronous
* so that observers are guaranteed a consistent behavior.
*/
_notifyOnLocationChange: function FullZoom__notifyOnLocationChange() {
this._executeSoon(function () {
Services.obs.notifyObservers(null, "browser-fullZoom:locationChange", "");
});
},
_executeSoon: function FullZoom__executeSoon(callback) {
if (!callback)
return;
Services.tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL);
},
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,595 @@
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
# 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/.
<menubar id="main-menubar"
onpopupshowing="if (event.target.parentNode.parentNode == this &amp;&amp;
!('@mozilla.org/widget/nativemenuservice;1' in Cc))
this.setAttribute('openedwithkey',
event.target.parentNode.openedWithKey);"
style="border:0px;padding:0px;margin:0px;-moz-appearance:none">
<menu id="file-menu" label="&fileMenu.label;"
accesskey="&fileMenu.accesskey;">
<menupopup id="menu_FilePopup">
<menuitem id="menu_newNavigatorTab"
label="&tabCmd.label;"
command="cmd_newNavigatorTab"
key="key_newNavigatorTab"
accesskey="&tabCmd.accesskey;"/>
<menuitem id="menu_newNavigator"
label="&newNavigatorCmd.label;"
accesskey="&newNavigatorCmd.accesskey;"
key="key_newNavigator"
command="cmd_newNavigator"/>
<menuitem id="menu_newPrivateWindow"
label="&newPrivateWindow.label;"
accesskey="&newPrivateWindow.accesskey;"
command="Tools:PrivateBrowsing"
key="key_privatebrowsing"/>
<menuitem id="menu_openLocation"
class="show-only-for-keyboard"
label="&openLocationCmd.label;"
command="Browser:OpenLocation"
key="focusURLBar"
accesskey="&openLocationCmd.accesskey;"/>
<menuitem id="menu_openFile"
label="&openFileCmd.label;"
command="Browser:OpenFile"
key="openFileKb"
accesskey="&openFileCmd.accesskey;"/>
<menuitem id="menu_close"
class="show-only-for-keyboard"
label="&closeCmd.label;"
key="key_close"
accesskey="&closeCmd.accesskey;"
command="cmd_close"/>
<menuitem id="menu_closeWindow"
class="show-only-for-keyboard"
hidden="true"
command="cmd_closeWindow"
key="key_closeWindow"
label="&closeWindow.label;"
accesskey="&closeWindow.accesskey;"/>
<menuseparator/>
<menuitem id="menu_savePage"
label="&savePageCmd.label;"
accesskey="&savePageCmd.accesskey;"
key="key_savePage"
command="Browser:SavePage"/>
<menuitem id="menu_sendLink"
label="&emailPageCmd.label;"
accesskey="&emailPageCmd.accesskey;"
command="Browser:SendLink"/>
<menuseparator/>
<menuitem id="menu_printSetup"
label="&printSetupCmd.label;"
accesskey="&printSetupCmd.accesskey;"
command="cmd_pageSetup"/>
#ifndef XP_MACOSX
<menuitem id="menu_printPreview"
label="&printPreviewCmd.label;"
accesskey="&printPreviewCmd.accesskey;"
command="cmd_printPreview"/>
#endif
<menuitem id="menu_print"
label="&printCmd.label;"
accesskey="&printCmd.accesskey;"
key="printKb"
command="cmd_print"/>
<menuseparator/>
<menuitem id="goOfflineMenuitem"
label="&goOfflineCmd.label;"
accesskey="&goOfflineCmd.accesskey;"
type="checkbox"
observes="workOfflineMenuitemState"
oncommand="BrowserOffline.toggleOfflineStatus();"/>
<menuitem id="menu_restart"
label="&appMenuRestart.label;"
accesskey="&appMenuRestart.accesskey;"
command="cmd_restartApplication"/>
<menuitem id="menu_FileQuitItem"
#ifdef XP_WIN
label="&quitApplicationCmdWin.label;"
accesskey="&quitApplicationCmdWin.accesskey;"
#else
#ifdef XP_MACOSX
label="&quitApplicationCmdMac.label;"
#else
label="&quitApplicationCmd.label;"
accesskey="&quitApplicationCmd.accesskey;"
#endif
#ifdef XP_UNIX
key="key_quitApplication"
#endif
#endif
command="cmd_quitApplication"/>
</menupopup>
</menu>
<menu id="edit-menu" label="&editMenu.label;"
accesskey="&editMenu.accesskey;">
<menupopup id="menu_EditPopup"
onpopupshowing="updateEditUIVisibility()"
onpopuphidden="updateEditUIVisibility()">
<menuitem id="menu_undo"
label="&undoCmd.label;"
key="key_undo"
accesskey="&undoCmd.accesskey;"
command="cmd_undo"/>
<menuitem id="menu_redo"
label="&redoCmd.label;"
key="key_redo"
accesskey="&redoCmd.accesskey;"
command="cmd_redo"/>
<menuseparator/>
<menuitem id="menu_cut"
label="&cutCmd.label;"
key="key_cut"
accesskey="&cutCmd.accesskey;"
command="cmd_cut"/>
<menuitem id="menu_copy"
label="&copyCmd.label;"
key="key_copy"
accesskey="&copyCmd.accesskey;"
command="cmd_copy"/>
<menuitem id="menu_paste"
label="&pasteCmd.label;"
key="key_paste"
accesskey="&pasteCmd.accesskey;"
command="cmd_paste"/>
<menuitem id="menu_delete"
label="&deleteCmd.label;"
key="key_delete"
accesskey="&deleteCmd.accesskey;"
command="cmd_delete"/>
<menuseparator/>
<menuitem id="menu_selectAll"
label="&selectAllCmd.label;"
key="key_selectAll"
accesskey="&selectAllCmd.accesskey;"
command="cmd_selectAll"/>
<menuseparator/>
<menuitem id="menu_find"
label="&findOnCmd.label;"
accesskey="&findOnCmd.accesskey;"
key="key_find"
command="cmd_find"/>
<menuitem id="menu_findAgain"
class="show-only-for-keyboard"
label="&findAgainCmd.label;"
accesskey="&findAgainCmd.accesskey;"
key="key_findAgain"
command="cmd_findAgain"/>
<menuseparator hidden="true" id="textfieldDirection-separator"/>
<menuitem id="textfieldDirection-swap"
command="cmd_switchTextDirection"
key="key_switchTextDirection"
label="&bidiSwitchTextDirectionItem.label;"
accesskey="&bidiSwitchTextDirectionItem.accesskey;"
hidden="true"/>
</menupopup>
</menu>
<menu id="view-menu" label="&viewMenu.label;"
accesskey="&viewMenu.accesskey;">
<menupopup id="menu_viewPopup"
onpopupshowing="updateCharacterEncodingMenuState();">
<menu id="viewToolbarsMenu"
label="&viewToolbarsMenu.label;"
accesskey="&viewToolbarsMenu.accesskey;">
<menupopup onpopupshowing="onViewToolbarsPopupShowing(event);">
<menuseparator/>
<menuitem id="menu_tabsOnTop"
command="cmd_ToggleTabsOnTop"
type="checkbox"
label="&viewTabsOnTop.label;"
accesskey="&viewTabsOnTop.accesskey;"/>
<menuitem id="menu_customizeToolbars"
label="&viewCustomizeToolbar.label;"
accesskey="&viewCustomizeToolbar.accesskey;"
command="cmd_CustomizeToolbars"/>
</menupopup>
</menu>
<menu id="viewSidebarMenuMenu"
label="&viewSidebarMenu.label;"
accesskey="&viewSidebarMenu.accesskey;">
<menupopup id="viewSidebarMenu">
<menuitem id="menu_bookmarksSidebar"
key="viewBookmarksSidebarKb"
observes="viewBookmarksSidebar"
label="&bookmarksButton.label;"/>
<menuitem id="menu_historySidebar"
key="key_gotoHistory"
observes="viewHistorySidebar"
label="&historyButton.label;"/>
</menupopup>
</menu>
<menuseparator/>
<menuitem id="menu_stop"
class="show-only-for-keyboard"
label="&stopCmd.label;"
accesskey="&stopCmd.accesskey;"
command="Browser:Stop"
#ifdef XP_MACOSX
key="key_stop_mac"/>
#else
key="key_stop"/>
#endif
<menuitem id="menu_reload"
class="show-only-for-keyboard"
label="&reloadCmd.label;"
accesskey="&reloadCmd.accesskey;"
key="key_reload"
command="Browser:ReloadOrDuplicate"
onclick="checkForMiddleClick(this, event);"/>
<menuseparator class="show-only-for-keyboard"/>
<menu id="viewFullZoomMenu" label="&fullZoom.label;"
accesskey="&fullZoom.accesskey;"
onpopupshowing="FullZoom.updateMenu();">
<menupopup>
<menuitem id="menu_zoomEnlarge"
key="key_fullZoomEnlarge"
label="&fullZoomEnlargeCmd.label;"
accesskey="&fullZoomEnlargeCmd.accesskey;"
command="cmd_fullZoomEnlarge"/>
<menuitem id="menu_zoomReduce"
key="key_fullZoomReduce"
label="&fullZoomReduceCmd.label;"
accesskey="&fullZoomReduceCmd.accesskey;"
command="cmd_fullZoomReduce"/>
<menuseparator/>
<menuitem id="menu_zoomReset"
key="key_fullZoomReset"
label="&fullZoomResetCmd.label;"
accesskey="&fullZoomResetCmd.accesskey;"
command="cmd_fullZoomReset"/>
<menuseparator/>
<menuitem id="toggle_zoom"
label="&fullZoomToggleCmd.label;"
accesskey="&fullZoomToggleCmd.accesskey;"
type="checkbox"
command="cmd_fullZoomToggle"
checked="false"/>
</menupopup>
</menu>
<menu id="pageStyleMenu" label="&pageStyleMenu.label;"
accesskey="&pageStyleMenu.accesskey;" observes="isImage">
<menupopup onpopupshowing="gPageStyleMenu.fillPopup(this);">
<menuitem id="menu_pageStyleNoStyle"
label="&pageStyleNoStyle.label;"
accesskey="&pageStyleNoStyle.accesskey;"
oncommand="gPageStyleMenu.disableStyle();"
type="radio"/>
<menuitem id="menu_pageStylePersistentOnly"
label="&pageStylePersistentOnly.label;"
accesskey="&pageStylePersistentOnly.accesskey;"
oncommand="gPageStyleMenu.switchStyleSheet('');"
type="radio"
checked="true"/>
<menuseparator/>
</menupopup>
</menu>
#include browser-charsetmenu.inc
<menuseparator/>
#ifdef XP_MACOSX
<menuitem id="enterFullScreenItem"
accesskey="&enterFullScreenCmd.accesskey;"
label="&enterFullScreenCmd.label;"
key="key_fullScreen">
<observes element="View:FullScreen" attribute="oncommand"/>
<observes element="View:FullScreen" attribute="disabled"/>
</menuitem>
<menuitem id="exitFullScreenItem"
accesskey="&exitFullScreenCmd.accesskey;"
label="&exitFullScreenCmd.label;"
key="key_fullScreen"
hidden="true">
<observes element="View:FullScreen" attribute="oncommand"/>
<observes element="View:FullScreen" attribute="disabled"/>
</menuitem>
#else
<menuitem id="fullScreenItem"
accesskey="&fullScreenCmd.accesskey;"
label="&fullScreenCmd.label;"
key="key_fullScreen"
type="checkbox"
observes="View:FullScreen"/>
#endif
<menuitem id="menu_showAllTabs"
hidden="true"
accesskey="&showAllTabsCmd.accesskey;"
label="&showAllTabsCmd.label;"
command="Browser:ShowAllTabs"
key="key_showAllTabs"/>
<menuseparator hidden="true" id="documentDirection-separator"/>
<menuitem id="documentDirection-swap"
hidden="true"
label="&bidiSwitchPageDirectionItem.label;"
accesskey="&bidiSwitchPageDirectionItem.accesskey;"
oncommand="SwitchDocumentDirection(window.content)"/>
</menupopup>
</menu>
<menu id="history-menu"
label="&historyMenu.label;"
accesskey="&historyMenu.accesskey;">
<menupopup id="goPopup"
#ifndef XP_MACOSX
placespopup="true"
#endif
context="placesContext"
oncommand="this.parentNode._placesView._onCommand(event);"
onclick="checkForMiddleClick(this, event);"
onpopupshowing="if (!this.parentNode._placesView)
new HistoryMenu(event);"
tooltip="bhTooltip"
popupsinherittooltip="true">
<menuitem id="historyMenuBack"
class="show-only-for-keyboard"
label="&backCmd.label;"
#ifdef XP_MACOSX
key="goBackKb2"
#else
key="goBackKb"
#endif
command="Browser:BackOrBackDuplicate"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="historyMenuForward"
class="show-only-for-keyboard"
label="&forwardCmd.label;"
#ifdef XP_MACOSX
key="goForwardKb2"
#else
key="goForwardKb"
#endif
command="Browser:ForwardOrForwardDuplicate"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="historyMenuHome"
class="show-only-for-keyboard"
label="&historyHomeCmd.label;"
oncommand="BrowserGoHome(event);"
onclick="checkForMiddleClick(this, event);"
key="goHome"/>
<menuseparator id="historyMenuHomeSeparator"
class="show-only-for-keyboard"/>
<menuitem id="menu_showAllHistory"
label="&showAllHistoryCmd2.label;"
#ifndef XP_MACOSX
class="menuitem-iconic"
key="showAllHistoryKb"
#endif
command="Browser:ShowAllHistory"/>
<menuitem id="sanitizeItem"
#ifndef XP_MACOSX
class="menuitem-iconic"
#endif
label="&clearRecentHistory.label;"
key="key_sanitize"
command="Tools:Sanitize"/>
<menuseparator id="sanitizeSeparator"/>
#ifdef MOZ_SERVICES_SYNC
<menuitem id="sync-tabs-menuitem"
class="syncTabsMenuItem"
label="&syncTabsMenu2.label;"
oncommand="BrowserOpenSyncTabs();"
disabled="true"/>
#endif
<menuitem id="historyRestoreLastSession"
label="&historyRestoreLastSession.label;"
command="Browser:RestoreLastSession"/>
<menu id="historyUndoMenu"
class="recentlyClosedTabsMenu"
label="&historyUndoMenu.label;"
disabled="true">
<menupopup id="historyUndoPopup"
#ifndef XP_MACOSX
placespopup="true"
#endif
onpopupshowing="document.getElementById('history-menu')._placesView.populateUndoSubmenu();"/>
</menu>
<menu id="historyUndoWindowMenu"
class="recentlyClosedWindowsMenu"
label="&historyUndoWindowMenu.label;"
disabled="true">
<menupopup id="historyUndoWindowPopup"
#ifndef XP_MACOSX
placespopup="true"
#endif
onpopupshowing="document.getElementById('history-menu')._placesView.populateUndoWindowSubmenu();"/>
</menu>
<menuseparator id="startHistorySeparator"
class="hide-if-empty-places-result"/>
</menupopup>
</menu>
<menu id="bookmarksMenu"
label="&bookmarksMenu.label;"
accesskey="&bookmarksMenu.accesskey;"
ondragenter="PlacesMenuDNDHandler.onDragEnter(event);"
ondragover="PlacesMenuDNDHandler.onDragOver(event);"
ondrop="PlacesMenuDNDHandler.onDrop(event);">
<menupopup id="bookmarksMenuPopup"
#ifndef XP_MACOSX
placespopup="true"
#endif
context="placesContext"
openInTabs="children"
oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
onpopupshowing="PlacesCommandHook.updateBookmarkAllTabsCommand();
if (!this.parentNode._placesView)
new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
tooltip="bhTooltip" popupsinherittooltip="true">
<menuitem id="bookmarksShowAll"
#ifndef XP_MACOSX
class="menuitem-iconic"
#endif
label="&organizeBookmarks.label;"
command="Browser:ShowAllBookmarks"
key="manBookmarkKb"/>
<menuseparator id="organizeBookmarksSeparator"/>
<menuitem id="menu_bookmarkThisPage"
#ifndef XP_MACOSX
class="menuitem-iconic"
#endif
label="&bookmarkThisPageCmd.label;"
command="Browser:AddBookmarkAs"
key="addBookmarkAsKb"/>
<menuitem id="subscribeToPageMenuitem"
#ifndef XP_MACOSX
class="menuitem-iconic"
#endif
label="&subscribeToPageMenuitem.label;"
oncommand="return FeedHandler.subscribeToFeed(null, event);"
onclick="checkForMiddleClick(this, event);"
observes="singleFeedMenuitemState"/>
<menu id="subscribeToPageMenupopup"
#ifndef XP_MACOSX
class="menu-iconic"
#endif
label="&subscribeToPageMenupopup.label;"
observes="multipleFeedsMenuState">
<menupopup id="subscribeToPageSubmenuMenupopup"
onpopupshowing="return FeedHandler.buildFeedList(event.target);"
oncommand="return FeedHandler.subscribeToFeed(null, event);"
onclick="checkForMiddleClick(this, event);"/>
</menu>
<menuitem id="menu_bookmarkAllTabs"
label="&addCurPagesCmd.label;"
class="show-only-for-keyboard"
command="Browser:BookmarkAllTabs"
key="bookmarkAllTabsKb"/>
<menuseparator id="bookmarksToolbarSeparator"/>
<menu id="bookmarksToolbarFolderMenu"
class="menu-iconic bookmark-item"
label="&personalbarCmd.label;"
container="true">
<menupopup id="bookmarksToolbarFolderPopup"
#ifndef XP_MACOSX
placespopup="true"
#endif
context="placesContext"
onpopupshowing="if (!this.parentNode._placesView)
new PlacesMenu(event, 'place:folder=TOOLBAR');"/>
</menu>
<menuseparator id="bookmarksMenuItemsSeparator"/>
<!-- Bookmarks menu items -->
<menuseparator builder="end"
class="hide-if-empty-places-result"/>
<menuitem id="menu_unsortedBookmarks"
#ifndef XP_MACOSX
class="menuitem-iconic"
#endif
label="&unsortedBookmarksCmd.label;"
oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');"/>
</menupopup>
</menu>
<menu id="tools-menu"
label="&toolsMenu.label;"
accesskey="&toolsMenu.accesskey;">
<menupopup id="menu_ToolsPopup"
#ifdef MOZ_SERVICES_SYNC
onpopupshowing="gSyncUI.updateUI();"
#endif
>
<menuitem id="menu_search"
class="show-only-for-keyboard"
label="&search.label;"
accesskey="&search.accesskey;"
key="key_search"
command="Tools:Search"/>
<menuseparator id="browserToolsSeparator"
class="show-only-for-keyboard"/>
<menuitem id="menu_openDownloads"
label="&downloads.label;"
accesskey="&downloads.accesskey;"
key="key_openDownloads"
command="Tools:Downloads"/>
<menuitem id="menu_openAddons"
label="&addons.label;"
accesskey="&addons.accesskey;"
key="key_openAddons"
command="Tools:Addons"/>
<menuitem id="menu_openPermissions"
label="&permissions.label;"
command="Tools:Permissions"
accesskey="&permissions.accesskey;"/>
#ifdef MOZ_SERVICES_SYNC
<!-- only one of sync-setup or sync-menu will be showing at once -->
<menuitem id="sync-setup"
label="&syncSetup.label;"
accesskey="&syncSetup.accesskey;"
observes="sync-setup-state"
oncommand="gSyncUI.openSetup()"/>
<menuitem id="sync-syncnowitem"
label="&syncSyncNowItem.label;"
accesskey="&syncSyncNowItem.accesskey;"
observes="sync-syncnow-state"
oncommand="gSyncUI.doSync(event);"/>
#endif
<menuseparator id="devToolsSeparator"/>
<menu id="webDeveloperMenu"
label="&webDeveloperMenu.label;"
accesskey="&webDeveloperMenu.accesskey;">
<menupopup id="menuWebDeveloperPopup">
#ifdef MOZ_DEVTOOLS
<menuitem id="menu_devToolbox"
observes="devtoolsMenuBroadcaster_DevToolbox"
accesskey="&devToolboxMenuItem.accesskey;"/>
<menuseparator id="menu_devtools_separator"/>
<menuitem id="menu_devToolbar"
observes="devtoolsMenuBroadcaster_DevToolbar"
accesskey="&devToolbarMenu.accesskey;"/>
<menuitem id="menu_chromeDebugger"
observes="devtoolsMenuBroadcaster_ChromeDebugger"/>
<menuitem id="menu_browserConsole"
observes="devtoolsMenuBroadcaster_BrowserConsole"
accesskey="&browserConsoleCmd.accesskey;"/>
<menuitem id="menu_responsiveUI"
observes="devtoolsMenuBroadcaster_ResponsiveUI"
accesskey="&responsiveDesignTool.accesskey;"/>
<menuitem id="menu_eyedropper"
observes="devtoolsMenuBroadcaster_Eyedropper"
accesskey="&eyedropper.accesskey;"/>
<menuitem id="menu_scratchpad"
observes="devtoolsMenuBroadcaster_Scratchpad"
accesskey="&scratchpad.accesskey;"/>
#endif
<menuitem id="menu_pageSource"
observes="devtoolsMenuBroadcaster_PageSource"
accesskey="&pageSourceCmd.accesskey;"/>
<menuitem id="javascriptConsole"
observes="devtoolsMenuBroadcaster_ErrorConsole"
accesskey="&errorConsoleCmd.accesskey;"/>
#ifdef MOZ_DEVTOOLS
<menuitem id="menu_devtools_connect"
observes="devtoolsMenuBroadcaster_connect"/>
#endif
<menuseparator id="devToolsEndSeparator"/>
<menuitem id="getMoreDevtools"
observes="devtoolsMenuBroadcaster_GetMoreTools"
accesskey="&getMoreDevtoolsCmd.accesskey;"/>
</menupopup>
</menu>
<menuitem id="menu_pageInfo"
accesskey="&pageInfoCmd.accesskey;"
label="&pageInfoCmd.label;"
#ifndef XP_WIN
key="key_viewInfo"
#endif
command="View:PageInfo"/>
<menuseparator id="prefSep"/>
<menuitem id="menu_preferences"
label="&preferencesCmd2.label;"
accesskey="&preferencesCmd2.accesskey;"
oncommand="openPreferences();"/>
</menupopup>
</menu>
#ifdef XP_MACOSX
<menu id="windowMenu" />
#endif
<menu id="helpMenu" />
</menubar>

View file

@ -0,0 +1,362 @@
// 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/.
//
// Based on original code by alice0775 https://github.com/alice0775
"use strict";
var browserMenuDragging = {
//-- config --
STAY_OPEN_ONDRAGEXIT: false,
DEBUG: false,
//-- config --
menupopup: ['bookmarksMenuPopup',
'PlacesToolbar',
'BMB_bookmarksPopup',
'appmenu_bookmarksPopup',
'BookmarksMenuToolButtonPopup',
'UnsortedBookmarksFolderToolButtonPopup',
'bookmarksMenuPopup-context'],
timer:[],
count:[],
init: function(){
window.removeEventListener('load', this, false);
window.addEventListener('unload', this, false);
this.addPrefListener(this.PrefListener);
window.addEventListener('aftercustomization', this, false);
this.initPref();
this.delayedStartup();
},
uninit: function(){
window.removeEventListener('unload', this, false);
this.removePrefListener(this.PrefListener);
window.removeEventListener('aftercustomization', this, false);
for (var i = 0; i < this.menupopup.length; i++){
var menupopup = document.getElementById(this.menupopup[i]);
if (menupopup){
menupopup.removeEventListener('popupshowing', this, false);
menupopup.removeEventListener('popuphiding', this, false);
}
}
},
initPref: function(){
this.STAY_OPEN_ONDRAGEXIT =
this.getPref('browser.menu.dragging.stayOpen',
'bool', false);
this.DEBUG =
this.getPref('browser.menu.dragging.debug',
'bool', false);
},
//delayed startup
delayedStartup: function(){
//wait until construction of bookmarksBarContent is completed.
for (var i = 0; i < this.menupopup.length; i++){
this.count[i] = 0;
this.timer[i] = setInterval(function(self, i){
if(++self.count[i] > 50 || document.getElementById(self.menupopup[i])){
clearInterval(self.timer[i]);
var menupopup = document.getElementById(self.menupopup[i]);
if (menupopup) {
menupopup.addEventListener('popupshowing', self, false);
menupopup.addEventListener('popuphiding', self, false);
}
}
}, 250, this, i);
}
},
handleEvent: function(event){
switch (event.type) {
case 'popupshowing':
this.popupshowing(event);
break;
case 'popuphiding':
this.popuphiding(event);
break;
case 'aftercustomization':
setTimeout(function(self){self.delayedStartup(self);}, 0, this);
break;
case 'load':
this.init();
break;
case 'unload':
this.uninit();
break;
}
},
popuphiding: function(event) {
var menupopup = event.originalTarget;
menupopup.parentNode.parentNode.openNode = null;
if (menupopup.parentNode.localName == 'toolbarbutton') {
// Fix for Bug 225434 - dragging bookmark from personal toolbar and releasing
// (on same bookmark or elsewhere) or clicking on bookmark menu then cancelling
// leaves button depressed/sunken when hovered
menupopup.parentNode.parentNode._openedMenuButton = null;
if (!PlacesControllerDragHelper.getSession())
// Clear the dragover attribute if present, if we are dragging into a
// folder in the hierachy of current opened popup we don't clear
// this attribute on clearOverFolder. See Notify for closeTimer.
if (menupopup.parentNode.hasAttribute('dragover'))
menupopup.parentNode.removeAttribute('dragover');
}
},
popupshowing: function(event) {
var menupopup = event.originalTarget;
browserMenuDragging.debug("popupshowing ===============\n" + menupopup.parentNode.getAttribute('label'));
var parentPopup = menupopup.parentNode.parentNode;
if (!!parentPopup.openNode){
try {
parentPopup.openNode.hidePopup();
} catch(e){}
}
parentPopup.openNode = menupopup;
menupopup.onDragStart = function (event) {
// Bug 555474 - While bookmark is dragged, the tooltip should not appear
browserMenuDragging.hideTooltip();
}
menupopup.onDragOver = function (event) {
// Bug 555474 - While bookmark is dragged, the tooltip should not appear
browserMenuDragging.hideTooltip();
var target = event.originalTarget;
while (target) {
if (/menupopup/.test(target.localName))
break;
target = target.parentNode;
}
if (this != target)
return;
event.stopPropagation();
browserMenuDragging.debug("onDragOver " + "\n" + this.parentNode.getAttribute('label'));
PlacesControllerDragHelper.currentDropTarget = event.target;
let dt = event.dataTransfer;
let dropPoint = this._getDropPoint(event);
if (!dropPoint || !dropPoint.ip ||
!PlacesControllerDragHelper.canDrop(dropPoint.ip, dt)) {
this._indicatorBar.hidden = true;
event.stopPropagation();
return;
}
// Mark this popup as being dragged over.
this.setAttribute('dragover', 'true');
if (dropPoint.folderElt) {
// We are dragging over a folder.
// _overFolder should take the care of opening it on a timer.
if (this._overFolder.elt &&
this._overFolder.elt != dropPoint.folderElt) {
}
if (!this._overFolder.elt) {
this._overFolder.elt = dropPoint.folderElt;
// Create the timer to open this folder.
this._overFolder.openTimer = this._overFolder
.setTimer(this._overFolder.hoverTime);
}
}
else {
// We are not dragging over a folder.
}
// Autoscroll the popup strip if we drag over the scroll buttons.
let anonid = event.originalTarget.getAttribute('anonid');
let scrollDir = anonid == 'scrollbutton-up' ? -1 :
anonid == 'scrollbutton-down' ? 1 : 0;
if (scrollDir != 0) {
this._scrollBox.scrollByIndex(scrollDir, false);
}
// Check if we should hide the drop indicator for this target.
if (dropPoint.folderElt || this._hideDropIndicator(event)) {
this._indicatorBar.hidden = true;
event.preventDefault();
event.stopPropagation();
return;
}
// We should display the drop indicator relative to the arrowscrollbox.
let sbo = this._scrollBox.scrollBoxObject;
let newMarginTop = 0;
if (scrollDir == 0) {
let elt = this.firstChild;
while (elt && event.screenY > elt.boxObject.screenY +
elt.boxObject.height / 2)
elt = elt.nextSibling;
newMarginTop = elt ? elt.boxObject.screenY - sbo.screenY :
sbo.height;
}
else if (scrollDir == 1)
newMarginTop = sbo.height;
// Set the new marginTop based on arrowscrollbox.
newMarginTop += sbo.y - this._scrollBox.boxObject.y;
this._indicatorBar.firstChild.style.marginTop = newMarginTop + 'px';
this._indicatorBar.hidden = false;
event.preventDefault();
event.stopPropagation();
}
menupopup.onDragExit = function (event) {
var target = event.originalTarget;
while (target) {
if (/menupopup/.test(target.localName))
break;
target = target.parentNode;
}
if (this != target)
return;
event.stopPropagation();
browserMenuDragging.debug("onDragExit " + browserMenuDragging.STAY_OPEN_ONDRAGEXIT);
PlacesControllerDragHelper.currentDropTarget = null;
this.removeAttribute('dragover');
// If we have not moved to a valid new target clear the drop indicator
// this happens when moving out of the popup.
target = event.relatedTarget;
if (!target)
this._indicatorBar.hidden = true;
// Close any folder being hovered over
if (this._overFolder.elt) {
this._overFolder.closeTimer = this._overFolder
.setTimer(this._overFolder.hoverTime);
}
// The auto-opened attribute is set when this folder was automatically
// opened after the user dragged over it. If this attribute is set,
// auto-close the folder on drag exit.
// We should also try to close this popup if the drag has started
// from here, the timer will check if we are dragging over a child.
if (this.hasAttribute('autoopened') ||
!browserMenuDragging.STAY_OPEN_ONDRAGEXIT &&
this.hasAttribute('dragstart')) {
this._overFolder.closeMenuTimer = this._overFolder
.setTimer(this._overFolder.hoverTime);
}
event.stopPropagation();
}
menupopup.addEventListener('dragstart', menupopup.onDragStart, true);
menupopup.addEventListener('dragover', menupopup.onDragOver, true);
menupopup.addEventListener('dragleave', menupopup.onDragExit, true);
},
hideTooltip: function() {
['bhTooltip', 'btTooltip2'].forEach(function(id) {
var tooltip = document.getElementById(id);
if (tooltip)
tooltip.hidePopup();
});
},
get getVer(){
const Cc = Components.classes;
const Ci = Components.interfaces;
var info = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
var ver = parseInt(info.version.substr(0,3) * 10,10) / 10;
return ver;
},
debug: function(aMsg){
if (!browserMenuDragging.DEBUG)
return;
Components.classes["@mozilla.org/consoleservice;1"]
.getService(Components.interfaces.nsIConsoleService)
.logStringMessage(aMsg);
},
getPref: function(aPrefString, aPrefType, aDefault){
var xpPref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService);
try{
switch (aPrefType){
case 'complex':
return xpPref.getComplexValue(aPrefString, Components.interfaces.nsILocalFile); break;
case 'str':
return xpPref.getCharPref(aPrefString).toString(); break;
case 'int':
return xpPref.getIntPref(aPrefString); break;
case 'bool':
default:
return xpPref.getBoolPref(aPrefString); break;
}
}catch(e){
}
return aDefault;
},
setPref: function(aPrefString, aPrefType, aValue){
var xpPref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService);
try{
switch (aPrefType){
case 'complex':
return xpPref.setComplexValue(aPrefString, Components.interfaces.nsILocalFile, aValue); break;
case 'str':
return xpPref.setCharPref(aPrefString, aValue); break;
case 'int':
aValue = parseInt(aValue);
return xpPref.setIntPref(aPrefString, aValue); break;
case 'bool':
default:
return xpPref.setBoolPref(aPrefString, aValue); break;
}
}catch(e){
}
return null;
},
addPrefListener: function(aObserver) {
try {
var pbi = Components.classes["@mozilla.org/preferences;1"].
getService(Components.interfaces.nsIPrefBranch2);
pbi.addObserver(aObserver.domain, aObserver, false);
} catch(e) {}
},
removePrefListener: function(aObserver) {
try {
var pbi = Components.classes["@mozilla.org/preferences;1"].
getService(Components.interfaces.nsIPrefBranch2);
pbi.removeObserver(aObserver.domain, aObserver);
} catch(e) {}
},
PrefListener:{
domain : 'browser.menu.dragging.stayOpen',
observe : function(aSubject, aTopic, aPrefstring) {
if (aTopic == 'nsPref:changed') {
browserMenuDragging.initPref();
}
}
}
}
window.addEventListener('load', browserMenuDragging, false);

View file

@ -0,0 +1,13 @@
<?xml version="1.0"?>
<overlay id="menuDraggingOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<window id="main-window">
<script type="application/x-javascript" src="chrome://browser/content/browser-menudragging.js" />
</window>
</overlay>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,797 @@
# -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# 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/.
const kPrefSessionPersistMinutes = "plugin.sessionPermissionNow.intervalInMinutes";
const kPrefPersistentDays = "plugin.persistentPermissionAlways.intervalInDays";
var gPluginHandler = {
PLUGIN_SCRIPTED_STATE_NONE: 0,
PLUGIN_SCRIPTED_STATE_FIRED: 1,
PLUGIN_SCRIPTED_STATE_DONE: 2,
getPluginUI: function (plugin, anonid) {
return plugin.ownerDocument.
getAnonymousElementByAttribute(plugin, "anonid", anonid);
},
_getPluginInfo: function (pluginElement) {
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
pluginElement.QueryInterface(Ci.nsIObjectLoadingContent);
let tagMimetype;
let pluginName = gNavigatorBundle.getString("pluginInfo.unknownPlugin");
let pluginTag = null;
let permissionString = null;
let fallbackType = null;
let blocklistState = null;
if (pluginElement instanceof HTMLAppletElement) {
tagMimetype = "application/x-java-vm";
} else {
tagMimetype = pluginElement.actualType;
if (tagMimetype == "") {
tagMimetype = pluginElement.type;
}
}
if (gPluginHandler.isKnownPlugin(pluginElement)) {
pluginTag = pluginHost.getPluginTagForType(pluginElement.actualType);
pluginName = gPluginHandler.makeNicePluginName(pluginTag.name);
permissionString = pluginHost.getPermissionStringForType(pluginElement.actualType);
fallbackType = pluginElement.defaultFallbackType;
blocklistState = pluginHost.getBlocklistStateForType(pluginElement.actualType);
// Make state-softblocked == state-notblocked for our purposes,
// they have the same UI. STATE_OUTDATED should not exist for plugin
// items, but let's alias it anyway, just in case.
if (blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED ||
blocklistState == Ci.nsIBlocklistService.STATE_OUTDATED) {
blocklistState = Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
}
}
return { mimetype: tagMimetype,
pluginName: pluginName,
pluginTag: pluginTag,
permissionString: permissionString,
fallbackType: fallbackType,
blocklistState: blocklistState,
};
},
// Map the plugin's name to a filtered version more suitable for user UI.
makeNicePluginName : function (aName) {
if (aName == "Shockwave Flash")
return "Adobe Flash";
// Clean up the plugin name by stripping off any trailing version numbers
// or "plugin". EG, "Foo Bar Plugin 1.23_02" --> "Foo Bar"
// Do this by first stripping the numbers, etc. off the end, and then
// removing "Plugin" (and then trimming to get rid of any whitespace).
// (Otherwise, something like "Java(TM) Plug-in 1.7.0_07" gets mangled)
let newName = aName.replace(/[\s\d\.\-\_\(\)]+$/, "").replace(/\bplug-?in\b/i, "").trim();
return newName;
},
isTooSmall : function (plugin, overlay) {
// Is the <object>'s size too small to hold what we want to show?
let pluginRect = plugin.getBoundingClientRect();
// XXX bug 446693. The text-shadow on the submitted-report text at
// the bottom causes scrollHeight to be larger than it should be.
// Clamp width/height to properly show CTP overlay on different
// zoom levels when embedded in iframes (rounding bug). (Bug 972237)
let overflows = (overlay.scrollWidth > Math.ceil(pluginRect.width)) ||
(overlay.scrollHeight - 5 > Math.ceil(pluginRect.height));
return overflows;
},
addLinkClickCallback: function (linkNode, callbackName /*callbackArgs...*/) {
// XXX just doing (callback)(arg) was giving a same-origin error. bug?
let self = this;
let callbackArgs = Array.prototype.slice.call(arguments).slice(2);
linkNode.addEventListener("click",
function(evt) {
if (!evt.isTrusted)
return;
evt.preventDefault();
if (callbackArgs.length == 0)
callbackArgs = [ evt ];
(self[callbackName]).apply(self, callbackArgs);
},
true);
linkNode.addEventListener("keydown",
function(evt) {
if (!evt.isTrusted)
return;
if (evt.keyCode == evt.DOM_VK_RETURN) {
evt.preventDefault();
if (callbackArgs.length == 0)
callbackArgs = [ evt ];
evt.preventDefault();
(self[callbackName]).apply(self, callbackArgs);
}
},
true);
},
// Helper to get the binding handler type from a plugin object
_getBindingType : function(plugin) {
if (!(plugin instanceof Ci.nsIObjectLoadingContent))
return null;
switch (plugin.pluginFallbackType) {
case Ci.nsIObjectLoadingContent.PLUGIN_UNSUPPORTED:
return "PluginNotFound";
case Ci.nsIObjectLoadingContent.PLUGIN_DISABLED:
return "PluginDisabled";
case Ci.nsIObjectLoadingContent.PLUGIN_BLOCKLISTED:
return "PluginBlocklisted";
case Ci.nsIObjectLoadingContent.PLUGIN_OUTDATED:
return "PluginOutdated";
case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY:
return "PluginClickToPlay";
case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE:
return "PluginVulnerableUpdatable";
case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE:
return "PluginVulnerableNoUpdate";
case Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW:
return "PluginPlayPreview";
default:
// Not all states map to a handler
return null;
}
},
handleEvent : function(event) {
let plugin;
let doc;
let eventType = event.type;
if (eventType === "PluginRemoved") {
doc = event.target;
}
else {
plugin = event.target;
doc = plugin.ownerDocument;
if (!(plugin instanceof Ci.nsIObjectLoadingContent))
return;
}
if (eventType == "PluginBindingAttached") {
// The plugin binding fires this event when it is created.
// As an untrusted event, ensure that this object actually has a binding
// and make sure we don't handle it twice
let overlay = this.getPluginUI(plugin, "main");
if (!overlay || overlay._bindingHandled) {
return;
}
overlay._bindingHandled = true;
// Lookup the handler for this binding
eventType = this._getBindingType(plugin);
if (!eventType) {
// Not all bindings have handlers
return;
}
}
let shouldShowNotification = false;
let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
if (!browser)
return;
switch (eventType) {
case "PluginCrashed":
this.pluginInstanceCrashed(plugin, event);
break;
case "PluginNotFound":
/* No action (plugin finder obsolete) */
break;
case "PluginBlocklisted":
case "PluginOutdated":
shouldShowNotification = true;
break;
case "PluginVulnerableUpdatable":
let updateLink = this.getPluginUI(plugin, "checkForUpdatesLink");
this.addLinkClickCallback(updateLink, "openPluginUpdatePage");
/* FALLTHRU */
case "PluginVulnerableNoUpdate":
case "PluginClickToPlay":
this._handleClickToPlayEvent(plugin);
let overlay = this.getPluginUI(plugin, "main");
let pluginName = this._getPluginInfo(plugin).pluginName;
let messageString = gNavigatorBundle.getFormattedString("PluginClickToActivate", [pluginName]);
let overlayText = this.getPluginUI(plugin, "clickToPlay");
overlayText.textContent = messageString;
if (eventType == "PluginVulnerableUpdatable" ||
eventType == "PluginVulnerableNoUpdate") {
let vulnerabilityString = gNavigatorBundle.getString(eventType);
let vulnerabilityText = this.getPluginUI(plugin, "vulnerabilityStatus");
vulnerabilityText.textContent = vulnerabilityString;
}
shouldShowNotification = true;
break;
case "PluginPlayPreview":
this._handlePlayPreviewEvent(plugin);
break;
case "PluginDisabled":
let manageLink = this.getPluginUI(plugin, "managePluginsLink");
this.addLinkClickCallback(manageLink, "managePlugins");
shouldShowNotification = true;
break;
case "PluginInstantiated":
//Pale Moon: don't show the indicator when plugins are enabled/allowed
if (gPrefService.getBoolPref("plugins.always_show_indicator")) {
shouldShowNotification = true;
}
break;
case "PluginRemoved":
shouldShowNotification = true;
break;
}
// Show the in-content UI if it's not too big. The crashed plugin handler already did this.
if (eventType != "PluginCrashed" && eventType != "PluginRemoved") {
let overlay = this.getPluginUI(plugin, "main");
if (overlay != null) {
if (!this.isTooSmall(plugin, overlay)) {
overlay.style.visibility = "visible";
}
plugin.addEventListener("overflow", function(event) {
overlay.style.visibility = "hidden";
});
plugin.addEventListener("underflow", function(event) {
// this is triggered if only one dimension underflows,
// the other dimension might still overflow
if (!gPluginHandler.isTooSmall(plugin, overlay)) {
overlay.style.visibility = "visible";
}
});
}
}
// Only show the notification after we've done the isTooSmall check, so
// that the notification can decide whether to show the "alert" icon
if (shouldShowNotification) {
this._showClickToPlayNotification(browser);
}
},
isKnownPlugin: function PH_isKnownPlugin(objLoadingContent) {
return (objLoadingContent.getContentTypeForMIMEType(objLoadingContent.actualType) ==
Ci.nsIObjectLoadingContent.TYPE_PLUGIN);
},
canActivatePlugin: function PH_canActivatePlugin(objLoadingContent) {
// if this isn't a known plugin, we can't activate it
// (this also guards pluginHost.getPermissionStringForType against
// unexpected input)
if (!gPluginHandler.isKnownPlugin(objLoadingContent))
return false;
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
let permissionString = pluginHost.getPermissionStringForType(objLoadingContent.actualType);
let principal = objLoadingContent.ownerDocument.defaultView.top.document.nodePrincipal;
let pluginPermission = Services.perms.testPermissionFromPrincipal(principal, permissionString);
let isFallbackTypeValid =
objLoadingContent.pluginFallbackType >= Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY &&
objLoadingContent.pluginFallbackType <= Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE;
if (objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW) {
// checking if play preview is subject to CTP rules
let playPreviewInfo = pluginHost.getPlayPreviewInfo(objLoadingContent.actualType);
isFallbackTypeValid = !playPreviewInfo.ignoreCTP;
}
return !objLoadingContent.activated &&
pluginPermission != Ci.nsIPermissionManager.DENY_ACTION &&
isFallbackTypeValid;
},
hideClickToPlayOverlay: function(aPlugin) {
let overlay = this.getPluginUI(aPlugin, "main");
if (overlay)
overlay.style.visibility = "hidden";
},
stopPlayPreview: function PH_stopPlayPreview(aPlugin, aPlayPlugin) {
let objLoadingContent = aPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
if (objLoadingContent.activated)
return;
if (aPlayPlugin)
objLoadingContent.playPlugin();
else
objLoadingContent.cancelPlayPreview();
},
// Callback for user clicking on a disabled plugin
managePlugins: function (aEvent) {
BrowserOpenAddonsMgr("addons://list/plugin");
},
// Callback for user clicking on the link in a click-to-play plugin
// (where the plugin has an update)
openPluginUpdatePage: function (aEvent) {
openURL(Services.urlFormatter.formatURLPref("plugins.update.url"));
},
// Callback for user clicking a "reload page" link
reloadPage: function (browser) {
browser.reload();
},
// Callback for user clicking the help icon
openHelpPage: function () {
openHelpLink("plugin-crashed", false);
},
// Event listener for click-to-play plugins.
_handleClickToPlayEvent: function PH_handleClickToPlayEvent(aPlugin) {
let doc = aPlugin.ownerDocument;
let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
let objLoadingContent = aPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
// guard against giving pluginHost.getPermissionStringForType a type
// not associated with any known plugin
if (!gPluginHandler.isKnownPlugin(objLoadingContent))
return;
let permissionString = pluginHost.getPermissionStringForType(objLoadingContent.actualType);
let principal = doc.defaultView.top.document.nodePrincipal;
let pluginPermission = Services.perms.testPermissionFromPrincipal(principal, permissionString);
let overlay = this.getPluginUI(aPlugin, "main");
if (pluginPermission == Ci.nsIPermissionManager.DENY_ACTION) {
if (overlay)
overlay.style.visibility = "hidden";
return;
}
if (overlay) {
overlay.addEventListener("click", gPluginHandler._overlayClickListener, true);
let closeIcon = gPluginHandler.getPluginUI(aPlugin, "closeIcon");
closeIcon.addEventListener("click", function(aEvent) {
if (aEvent.button == 0 && aEvent.isTrusted)
gPluginHandler.hideClickToPlayOverlay(aPlugin);
}, true);
}
},
_overlayClickListener: {
handleEvent: function PH_handleOverlayClick(aEvent) {
let plugin = document.getBindingParent(aEvent.target);
let contentWindow = plugin.ownerDocument.defaultView.top;
// gBrowser.getBrowserForDocument does not exist in the case where we
// drag-and-dropped a tab from a window containing only that tab. In
// that case, the window gets destroyed.
let browser = gBrowser.getBrowserForDocument ?
gBrowser.getBrowserForDocument(contentWindow.document) :
null;
// If browser is null here, we've been drag-and-dropped from another
// window, and this is the wrong click handler.
if (!browser) {
aEvent.target.removeEventListener("click", gPluginHandler._overlayClickListener, true);
return;
}
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
// Have to check that the target is not the link to update the plugin
if (!(aEvent.originalTarget instanceof HTMLAnchorElement) &&
(aEvent.originalTarget.getAttribute('anonid') != 'closeIcon') &&
aEvent.button == 0 && aEvent.isTrusted) {
gPluginHandler._showClickToPlayNotification(browser, plugin);
aEvent.stopPropagation();
aEvent.preventDefault();
}
}
},
_handlePlayPreviewEvent: function PH_handlePlayPreviewEvent(aPlugin) {
let doc = aPlugin.ownerDocument;
let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
let pluginInfo = this._getPluginInfo(aPlugin);
let playPreviewInfo = pluginHost.getPlayPreviewInfo(pluginInfo.mimetype);
let previewContent = this.getPluginUI(aPlugin, "previewPluginContent");
let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
if (!iframe) {
// lazy initialization of the iframe
iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
iframe.className = "previewPluginContentFrame";
previewContent.appendChild(iframe);
// Force a style flush, so that we ensure our binding is attached.
aPlugin.clientTop;
}
iframe.src = playPreviewInfo.redirectURL;
// MozPlayPlugin event can be dispatched from the extension chrome
// code to replace the preview content with the native plugin
previewContent.addEventListener("MozPlayPlugin", function playPluginHandler(aEvent) {
if (!aEvent.isTrusted)
return;
previewContent.removeEventListener("MozPlayPlugin", playPluginHandler, true);
let playPlugin = !aEvent.detail;
gPluginHandler.stopPlayPreview(aPlugin, playPlugin);
// cleaning up: removes overlay iframe from the DOM
let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
if (iframe)
previewContent.removeChild(iframe);
}, true);
if (!playPreviewInfo.ignoreCTP) {
gPluginHandler._showClickToPlayNotification(browser);
}
},
reshowClickToPlayNotification: function PH_reshowClickToPlayNotification() {
let browser = gBrowser.selectedBrowser;
let contentWindow = browser.contentWindow;
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let doc = contentWindow.document;
let plugins = cwu.plugins;
for (let plugin of plugins) {
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
if (overlay)
overlay.removeEventListener("click", gPluginHandler._overlayClickListener, true);
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
if (gPluginHandler.canActivatePlugin(objLoadingContent))
gPluginHandler._handleClickToPlayEvent(plugin);
}
gPluginHandler._showClickToPlayNotification(browser);
},
_clickToPlayNotificationEventCallback: function PH_ctpEventCallback(event) {
if (event == "showing") {
gPluginHandler._makeCenterActions(this);
}
else if (event == "dismissed") {
// Once the popup is dismissed, clicking the icon should show the full
// list again
this.options.primaryPlugin = null;
}
},
// Match the behaviour of nsPermissionManager
_getHostFromPrincipal: function PH_getHostFromPrincipal(principal) {
if (!principal.URI || principal.URI.schemeIs("moz-nullprincipal")) {
return "(null)";
}
try {
if (principal.URI.host)
return principal.URI.host;
} catch (e) {}
return principal.origin;
},
_makeCenterActions: function PH_makeCenterActions(notification) {
let contentWindow = notification.browser.contentWindow;
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let principal = contentWindow.document.nodePrincipal;
// This matches the behavior of nsPermssionManager, used for display purposes only
let principalHost = this._getHostFromPrincipal(principal);
let centerActions = [];
let pluginsFound = new Set();
for (let plugin of cwu.plugins) {
plugin.QueryInterface(Ci.nsIObjectLoadingContent);
if (plugin.getContentTypeForMIMEType(plugin.actualType) != Ci.nsIObjectLoadingContent.TYPE_PLUGIN) {
continue;
}
let pluginInfo = this._getPluginInfo(plugin);
if (pluginInfo.permissionString === null) {
Components.utils.reportError("No permission string for active plugin.");
continue;
}
if (pluginsFound.has(pluginInfo.permissionString)) {
continue;
}
pluginsFound.add(pluginInfo.permissionString);
// Add the per-site permissions and details URLs to pluginInfo here
// because they are more expensive to compute and so we avoid it in
// the tighter loop above.
let permissionObj = Services.perms.
getPermissionObject(principal, pluginInfo.permissionString, false);
if (permissionObj) {
pluginInfo.pluginPermissionHost = permissionObj.host;
pluginInfo.pluginPermissionType = permissionObj.expireType;
}
else {
pluginInfo.pluginPermissionHost = principalHost;
pluginInfo.pluginPermissionType = undefined;
}
let url;
// TODO: allow the blocklist to specify a better link, bug 873093
if (pluginInfo.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE) {
url = Services.urlFormatter.formatURLPref("plugins.update.url");
}
else if (pluginInfo.blocklistState != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
url = Services.blocklist.getPluginBlocklistURL(pluginInfo.pluginTag);
}
pluginInfo.detailsLink = url;
centerActions.push(pluginInfo);
}
centerActions.sort(function(a, b) {
return a.pluginName.localeCompare(b.pluginName);
});
notification.options.centerActions = centerActions;
},
/**
* Called from the plugin doorhanger to set the new permissions for a plugin
* and activate plugins if necessary.
* aNewState should be either "allownow" "allowalways" or "block"
*/
_updatePluginPermission: function PH_setPermissionForPlugins(aNotification, aPluginInfo, aNewState) {
let permission;
let expireType;
let expireTime;
switch (aNewState) {
case "allownow":
permission = Ci.nsIPermissionManager.ALLOW_ACTION;
expireType = Ci.nsIPermissionManager.EXPIRE_SESSION;
expireTime = Date.now() + Services.prefs.getIntPref(kPrefSessionPersistMinutes) * 60 * 1000;
break;
case "allowalways":
permission = Ci.nsIPermissionManager.ALLOW_ACTION;
expireType = Ci.nsIPermissionManager.EXPIRE_TIME;
expireTime = Date.now() +
Services.prefs.getIntPref(kPrefPersistentDays) * 24 * 60 * 60 * 1000;
break;
case "block":
permission = Ci.nsIPermissionManager.PROMPT_ACTION;
expireType = Ci.nsIPermissionManager.EXPIRE_NEVER;
expireTime = 0;
break;
// In case a plugin has already been allowed in another tab, the "continue allowing" button
// shouldn't change any permissions but should run the plugin-enablement code below.
case "continue":
break;
default:
Cu.reportError(Error("Unexpected plugin state: " + aNewState));
return;
}
let browser = aNotification.browser;
let contentWindow = browser.contentWindow;
if (aNewState != "continue") {
let principal = contentWindow.document.nodePrincipal;
Services.perms.addFromPrincipal(principal, aPluginInfo.permissionString,
permission, expireType, expireTime);
if (aNewState == "block") {
return;
}
}
// Manually activate the plugins that would have been automatically
// activated.
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let plugins = cwu.plugins;
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
for (let plugin of plugins) {
plugin.QueryInterface(Ci.nsIObjectLoadingContent);
// canActivatePlugin will return false if this isn't a known plugin type,
// so the pluginHost.getPermissionStringForType call is protected
if (gPluginHandler.canActivatePlugin(plugin) &&
aPluginInfo.permissionString == pluginHost.getPermissionStringForType(plugin.actualType)) {
plugin.playPlugin();
}
}
},
_showClickToPlayNotification: function PH_showClickToPlayNotification(aBrowser, aPrimaryPlugin) {
let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser);
let contentWindow = aBrowser.contentWindow;
let contentDoc = aBrowser.contentDocument;
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
// Pale Moon: cwu.plugins may contain non-plugin <object>s, filter them out
let plugins = cwu.plugins.filter(function(plugin) {
return (plugin.getContentTypeForMIMEType(plugin.actualType) ==
Ci.nsIObjectLoadingContent.TYPE_PLUGIN);
});
if (plugins.length == 0) {
if (notification) {
PopupNotifications.remove(notification);
}
return;
}
let icon = 'plugins-notification-icon';
for (let plugin of plugins) {
let fallbackType = plugin.pluginFallbackType;
if (fallbackType == plugin.PLUGIN_VULNERABLE_UPDATABLE ||
fallbackType == plugin.PLUGIN_VULNERABLE_NO_UPDATE ||
fallbackType == plugin.PLUGIN_BLOCKLISTED) {
icon = 'blocked-plugins-notification-icon';
break;
}
if (fallbackType == plugin.PLUGIN_CLICK_TO_PLAY) {
let overlay = contentDoc.getAnonymousElementByAttribute(plugin, "anonid", "main");
if (!overlay || overlay.style.visibility == 'hidden') {
icon = 'alert-plugins-notification-icon';
}
}
}
let dismissed = notification ? notification.dismissed : true;
if (aPrimaryPlugin)
dismissed = false;
let primaryPluginPermission = null;
if (aPrimaryPlugin) {
primaryPluginPermission = this._getPluginInfo(aPrimaryPlugin).permissionString;
}
let options = {
dismissed: dismissed,
eventCallback: this._clickToPlayNotificationEventCallback,
primaryPlugin: primaryPluginPermission
};
PopupNotifications.show(aBrowser, "click-to-play-plugins",
"", icon,
null, null, options);
},
// Crashed-plugin observer. Notified once per plugin crash, before events
// are dispatched to individual plugin instances.
pluginCrashed : function(subject, topic, data) {
let propertyBag = subject;
if (!(propertyBag instanceof Ci.nsIPropertyBag2) ||
!(propertyBag instanceof Ci.nsIWritablePropertyBag2))
return;
},
// Crashed-plugin event listener. Called for every instance of a
// plugin in content.
pluginInstanceCrashed: function (plugin, aEvent) {
// Ensure the plugin and event are of the right type.
if (!(aEvent instanceof Ci.nsIDOMDataContainerEvent))
return;
let submittedReport = aEvent.getData("submittedCrashReport");
let doPrompt = true; // XXX followup for .getData("doPrompt");
let submitReports = true; // XXX followup for .getData("submitReports");
let pluginName = aEvent.getData("pluginName");
let pluginDumpID = aEvent.getData("pluginDumpID");
let browserDumpID = aEvent.getData("browserDumpID");
// Remap the plugin name to a more user-presentable form.
pluginName = this.makeNicePluginName(pluginName);
let messageString = gNavigatorBundle.getFormattedString("crashedpluginsMessage.title", [pluginName]);
//
// Configure the crashed-plugin placeholder.
//
// Force a layout flush so the binding is attached.
plugin.clientTop;
let doc = plugin.ownerDocument;
let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
let statusDiv = doc.getAnonymousElementByAttribute(plugin, "class", "submitStatus");
let crashText = doc.getAnonymousElementByAttribute(plugin, "class", "msgCrashedText");
crashText.textContent = messageString;
let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
let link = doc.getAnonymousElementByAttribute(plugin, "class", "reloadLink");
this.addLinkClickCallback(link, "reloadPage", browser);
let notificationBox = gBrowser.getNotificationBox(browser);
let isShowing = true;
// Is the <object>'s size too small to hold what we want to show?
if (this.isTooSmall(plugin, overlay)) {
// First try hiding the crash report submission UI.
statusDiv.removeAttribute("status");
if (this.isTooSmall(plugin, overlay)) {
// Hide the overlay's contents. Use visibility style, so that it doesn't
// collapse down to 0x0.
overlay.style.visibility = "hidden";
isShowing = false;
}
}
if (isShowing) {
// If a previous plugin on the page was too small and resulted in adding a
// notification bar, then remove it because this plugin instance it big
// enough to serve as in-content notification.
hideNotificationBar();
doc.mozNoPluginCrashedNotification = true;
} else {
// If another plugin on the page was large enough to show our UI, we don't
// want to show a notification bar.
if (!doc.mozNoPluginCrashedNotification)
showNotificationBar(pluginDumpID, browserDumpID);
}
function hideNotificationBar() {
let notification = notificationBox.getNotificationWithValue("plugin-crashed");
if (notification)
notificationBox.removeNotification(notification, true);
}
function showNotificationBar(pluginDumpID, browserDumpID) {
// If there's already an existing notification bar, don't do anything.
let notification = notificationBox.getNotificationWithValue("plugin-crashed");
if (notification)
return;
// Configure the notification bar
let priority = notificationBox.PRIORITY_WARNING_MEDIUM;
let iconURL = "chrome://mozapps/skin/plugins/notifyPluginCrashed.png";
let reloadLabel = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.label");
let reloadKey = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.accesskey");
let submitLabel = gNavigatorBundle.getString("crashedpluginsMessage.submitButton.label");
let submitKey = gNavigatorBundle.getString("crashedpluginsMessage.submitButton.accesskey");
let buttons = [{
label: reloadLabel,
accessKey: reloadKey,
popup: null,
callback: function() { browser.reload(); },
}];
notification = notificationBox.appendNotification(messageString, "plugin-crashed",
iconURL, priority, buttons);
// Add the "learn more" link.
let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
let link = notification.ownerDocument.createElementNS(XULNS, "label");
link.className = "text-link";
link.setAttribute("value", gNavigatorBundle.getString("crashedpluginsMessage.learnMore"));
let crashurl = formatURL("app.support.baseURL", true);
crashurl += "plugin-crashed-notificationbar";
link.href = crashurl;
let description = notification.ownerDocument.getAnonymousElementByAttribute(notification, "anonid", "messageText");
description.appendChild(link);
// Remove the notfication when the page is reloaded.
doc.defaultView.top.addEventListener("unload", function() {
notificationBox.removeNotification(notification);
}, false);
}
}
};

View file

@ -0,0 +1,436 @@
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
# 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/.
#ifdef XP_UNIX
#ifndef XP_MACOSX
#define XP_GNOME 1
#endif
#endif
<stringbundleset id="stringbundleset">
<stringbundle id="bundle_brand" src="chrome://branding/locale/brand.properties"/>
<stringbundle id="bundle_shell" src="chrome://browser/locale/shellservice.properties"/>
<stringbundle id="bundle_preferences" src="chrome://browser/locale/preferences/preferences.properties"/>
</stringbundleset>
<commandset id="mainCommandSet">
<command id="cmd_newNavigator" oncommand="OpenBrowserWindow()"/>
<command id="cmd_handleBackspace" oncommand="BrowserHandleBackspace();" />
<command id="cmd_handleShiftBackspace" oncommand="BrowserHandleShiftBackspace();" />
<command id="cmd_newNavigatorTab" oncommand="BrowserOpenTab();"/>
<command id="Browser:OpenFile" oncommand="BrowserOpenFileWindow();"/>
<command id="Browser:SavePage" oncommand="saveDocument(window.content.document);"/>
<command id="Browser:SendLink"
oncommand="MailIntegration.sendLinkForWindow(window.content);"/>
<command id="cmd_pageSetup" oncommand="PrintUtils.showPageSetup();"/>
<command id="cmd_print" oncommand="PrintUtils.print();"/>
<command id="cmd_printPreview" oncommand="PrintUtils.printPreview(PrintPreviewListener);"/>
<command id="cmd_close" oncommand="BrowserCloseTabOrWindow()"/>
<command id="cmd_closeWindow" oncommand="BrowserTryToCloseWindow()"/>
<command id="cmd_ToggleTabsOnTop" oncommand="TabsOnTop.toggle()"/>
<command id="cmd_CustomizeToolbars" oncommand="BrowserCustomizeToolbar()"/>
<command id="cmd_restartApplication" oncommand="restart(false);"/>
<command id="cmd_quitApplication" oncommand="goQuitApplication()"/>
<commandset id="editMenuCommands"/>
<command id="View:PageSource" oncommand="BrowserViewSourceOfDocument(content.document);" observes="isImage"/>
<command id="View:PageInfo" oncommand="BrowserPageInfo();"/>
<command id="View:FullScreen" oncommand="BrowserFullScreen();"/>
<command id="cmd_find"
oncommand="gFindBar.onFindCommand();"
observes="isImage"/>
<command id="cmd_findAgain"
oncommand="gFindBar.onFindAgainCommand(false);"
observes="isImage"/>
<command id="cmd_findPrevious"
oncommand="gFindBar.onFindAgainCommand(true);"
observes="isImage"/>
<!-- work-around bug 392512 -->
<command id="Browser:AddBookmarkAs"
oncommand="PlacesCommandHook.bookmarkCurrentPage(true, PlacesUtils.bookmarksMenuFolderId);"/>
<!-- The command disabled state must be manually updated through
PlacesCommandHook.updateBookmarkAllTabsCommand() -->
<command id="Browser:BookmarkAllTabs"
oncommand="PlacesCommandHook.bookmarkCurrentPages();"/>
<command id="Browser:Home" oncommand="BrowserHome();"/>
<command id="Browser:Back" oncommand="BrowserBack();" disabled="true"/>
<command id="Browser:BackOrBackDuplicate" oncommand="BrowserBack(event);" disabled="true">
<observes element="Browser:Back" attribute="disabled"/>
</command>
<command id="Browser:Forward" oncommand="BrowserForward();" disabled="true"/>
<command id="Browser:ForwardOrForwardDuplicate" oncommand="BrowserForward(event);" disabled="true">
<observes element="Browser:Forward" attribute="disabled"/>
</command>
<command id="Browser:Stop" oncommand="BrowserStop();" disabled="true"/>
<command id="Browser:Reload" oncommand="if (event.shiftKey) BrowserReloadSkipCache(); else BrowserReload()" disabled="true"/>
<command id="Browser:ReloadOrDuplicate" oncommand="BrowserReloadOrDuplicate(event)" disabled="true">
<observes element="Browser:Reload" attribute="disabled"/>
</command>
<command id="Browser:ReloadSkipCache" oncommand="BrowserReloadSkipCache()" disabled="true">
<observes element="Browser:Reload" attribute="disabled"/>
</command>
<command id="Browser:NextTab" oncommand="gBrowser.tabContainer.advanceSelectedTab(1, true);"/>
<command id="Browser:PrevTab" oncommand="gBrowser.tabContainer.advanceSelectedTab(-1, true);"/>
<command id="Browser:ShowAllTabs" oncommand="allTabs.open();"/>
<command id="Browser:FocusNextFrame" oncommand="focusNextFrame(event);"/>
<command id="cmd_fullZoomReduce" oncommand="FullZoom.reduce()"/>
<command id="cmd_fullZoomEnlarge" oncommand="FullZoom.enlarge()"/>
<command id="cmd_fullZoomReset" oncommand="FullZoom.reset()"/>
<command id="cmd_fullZoomToggle" oncommand="ZoomManager.toggleZoom();"/>
<command id="cmd_gestureRotateLeft" oncommand="gGestureSupport.rotate(event.sourceEvent)"/>
<command id="cmd_gestureRotateRight" oncommand="gGestureSupport.rotate(event.sourceEvent)"/>
<command id="cmd_gestureRotateEnd" oncommand="gGestureSupport.rotateEnd()"/>
<command id="Browser:OpenLocation" oncommand="openLocation();"/>
<command id="Browser:RestoreLastSession" oncommand="restoreLastSession();" disabled="true"/>
<command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
<command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
#ifdef MOZ_DEVTOOLS
<command id="Tools:DevToolbox" oncommand="gDevToolsBrowser.toggleToolboxCommand(gBrowser);"/>
<command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true" hidden="true"/>
<command id="Tools:DevToolbarFocus" oncommand="DeveloperToolbar.focusToggle();" disabled="true"/>
<command id="Tools:DevAppMgr" oncommand="gDevToolsBrowser.openAppManager(gBrowser);" disabled="true" hidden="true"/>
<command id="Tools:WebIDE" oncommand="gDevToolsBrowser.openWebIDE();" disabled="true" hidden="true"/>
<command id="Tools:ChromeDebugger" oncommand="BrowserToolboxProcess.init();" disabled="true" hidden="true"/>
<command id="Tools:BrowserConsole" oncommand="HUDService.openBrowserConsoleOrFocus();"/>
<command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true" hidden="true"/>
<command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true" hidden="true"/>
<command id="Tools:Eyedropper" oncommand="openEyedropper();"/>
#endif
<command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
<command id="Tools:Permissions" oncommand="BrowserOpenPermissionsMgr();"/>
<command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/>
#ifdef MOZ_DEVTOOLS
<command id="Tools:DevToolsConnect" oncommand="gDevToolsBrowser.openConnectScreen(gBrowser)" disabled="true" hidden="true"/>
#endif
<command id="Tools:Sanitize"
oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
<command id="Tools:PrivateBrowsing"
oncommand="OpenBrowserWindow({private: true});"/>
<command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
<command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
<command id="Browser:ToggleAddonBar" oncommand="toggleAddonBar();"/>
</commandset>
<commandset id="placesCommands">
<command id="Browser:ShowAllBookmarks"
oncommand="PlacesCommandHook.showPlacesOrganizer('AllBookmarks');"/>
<command id="Browser:ShowAllHistory"
oncommand="PlacesCommandHook.showPlacesOrganizer('History');"/>
</commandset>
<broadcasterset id="mainBroadcasterSet">
<broadcaster id="viewBookmarksSidebar" autoCheck="false" sidebartitle="&bookmarksButton.label;"
type="checkbox" group="sidebar" sidebarurl="chrome://browser/content/bookmarks/bookmarksPanel.xul"
oncommand="toggleSidebar('viewBookmarksSidebar');"/>
<!-- for both places and non-places, the sidebar lives at
chrome://browser/content/history/history-panel.xul so there are no
problems when switching between versions -->
<broadcaster id="viewHistorySidebar" autoCheck="false" sidebartitle="&historyButton.label;"
type="checkbox" group="sidebar"
sidebarurl="chrome://browser/content/history/history-panel.xul"
oncommand="toggleSidebar('viewHistorySidebar');"/>
<broadcaster id="viewWebPanelsSidebar" autoCheck="false"
type="checkbox" group="sidebar" sidebarurl="chrome://browser/content/web-panels.xul"
oncommand="toggleSidebar('viewWebPanelsSidebar');"/>
<!-- popup blocking menu items -->
<broadcaster id="blockedPopupAllowSite"
accesskey="&allowPopups.accesskey;"
oncommand="gPopupBlockerObserver.toggleAllowPopupsForSite(event);"/>
<broadcaster id="blockedPopupEditSettings"
#ifdef XP_WIN
label="&editPopupSettings.label;"
#else
label="&editPopupSettingsUnix.label;"
#endif
accesskey="&editPopupSettings.accesskey;"
oncommand="gPopupBlockerObserver.editPopupSettings();"/>
<broadcaster id="blockedPopupDontShowMessage"
accesskey="&dontShowMessage.accesskey;"
type="checkbox"
oncommand="gPopupBlockerObserver.dontShowMessage();"/>
<broadcaster id="blockedPopupsSeparator"/>
<broadcaster id="isImage"/>
<broadcaster id="isFrameImage"/>
<broadcaster id="singleFeedMenuitemState" disabled="true"/>
<broadcaster id="multipleFeedsMenuState" hidden="true"/>
#ifdef MOZ_SERVICES_SYNC
<broadcaster id="sync-setup-state"/>
<broadcaster id="sync-syncnow-state"/>
#endif
<broadcaster id="workOfflineMenuitemState"/>
#ifdef MOZ_DEVTOOLS
<!-- DevTools broadcasters -->
<broadcaster id="devtoolsMenuBroadcaster_DevToolbox"
label="&devToolboxMenuItem.label;"
type="checkbox" autocheck="false"
command="Tools:DevToolbox"
key="key_devToolbox"/>
<broadcaster id="devtoolsMenuBroadcaster_DevToolbar"
label="&devToolbarMenu.label;"
type="checkbox" autocheck="false"
command="Tools:DevToolbar"
key="key_devToolbar"/>
<broadcaster id="devtoolsMenuBroadcaster_DevAppMgr"
label="&devAppMgrMenu.label;"
command="Tools:DevAppMgr"/>
<broadcaster id="devtoolsMenuBroadcaster_webide"
label="&webide.label;"
command="Tools:WebIDE"
key="key_webide"/>
<broadcaster id="devtoolsMenuBroadcaster_ChromeDebugger"
label="&chromeDebuggerMenu.label;"
command="Tools:ChromeDebugger"/>
<broadcaster id="devtoolsMenuBroadcaster_BrowserConsole"
label="&browserConsoleCmd.label;"
key="key_browserConsole"
command="Tools:BrowserConsole"/>
<broadcaster id="devtoolsMenuBroadcaster_Scratchpad"
label="&scratchpad.label;"
command="Tools:Scratchpad"
key="key_scratchpad"/>
<broadcaster id="devtoolsMenuBroadcaster_ResponsiveUI"
label="&responsiveDesignTool.label;"
type="checkbox" autocheck="false"
command="Tools:ResponsiveUI"
key="key_responsiveUI"/>
<broadcaster id="devtoolsMenuBroadcaster_Eyedropper"
label="&eyedropper.label;"
type="checkbox" autocheck="false"
command="Tools:Eyedropper"/>
#endif
<broadcaster id="devtoolsMenuBroadcaster_PageSource"
label="&pageSourceCmd.label;"
key="key_viewSource"
command="View:PageSource"/>
<broadcaster id="devtoolsMenuBroadcaster_ErrorConsole"
label="&errorConsoleCmd.label;"
command="Tools:ErrorConsole"/>
<broadcaster id="devtoolsMenuBroadcaster_GetMoreTools"
label="&getMoreDevtoolsCmd.label;"
oncommand="openUILinkIn(gPrefService.getCharPref('browser.getdevtools.url'), 'tab');"/>
#ifdef MOZ_DEVTOOLS
<broadcaster id="devtoolsMenuBroadcaster_connect"
label="&devtoolsConnect.label;"
command="Tools:DevToolsConnect"/>
#endif
</broadcasterset>
<keyset id="mainKeyset">
<key id="key_newNavigator"
key="&newNavigatorCmd.key;"
command="cmd_newNavigator"
modifiers="accel"/>
<key id="key_newNavigatorTab" key="&tabCmd.commandkey;" modifiers="accel" command="cmd_newNavigatorTab"/>
<key id="focusURLBar" key="&openCmd.commandkey;" command="Browser:OpenLocation"
modifiers="accel"/>
#ifndef XP_MACOSX
<key id="focusURLBar2" key="&urlbar.accesskey;" command="Browser:OpenLocation"
modifiers="alt"/>
#endif
#
# Search Command Key Logic works like this:
#
# Unix: Ctrl+K (cross platform binding)
# Ctrl+J (in case of emacs Ctrl-K conflict)
# Mac: Cmd+K (cross platform binding)
# Cmd+Opt+F (platform convention)
# Win: Ctrl+K (cross platform binding)
# Ctrl+E (IE compat)
#
# We support Ctrl+K on all platforms now and advertise it in the menu since it is
# our standard - it is a "safe" choice since it is near no harmful keys like "W" as
# "E" is. People mourning the loss of Ctrl+K for emacs compat can switch their GTK
# system setting to use emacs emulation, and we should respect it. Focus-Search-Box
# is a fundamental keybinding and we are maintaining a XP binding so that it is easy
# for people to switch to Linux.
#
<key id="key_search" key="&searchFocus.commandkey;" command="Tools:Search" modifiers="accel"/>
#ifdef XP_MACOSX
<key id="key_search2" key="&findOnCmd.commandkey;" command="Tools:Search" modifiers="accel,alt"/>
#endif
#ifdef XP_WIN
<key id="key_search2" key="&searchFocus.commandkey2;" command="Tools:Search" modifiers="accel"/>
#endif
#ifdef XP_GNOME
<key id="key_search2" key="&searchFocusUnix.commandkey;" command="Tools:Search" modifiers="accel"/>
<key id="key_openDownloads" key="&downloadsUnix.commandkey;" command="Tools:Downloads" modifiers="accel,shift"/>
#else
<key id="key_openDownloads" key="&downloads.commandkey;" command="Tools:Downloads" modifiers="accel"/>
#endif
<key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/>
#ifdef MOZ_DEVTOOLS
<key id="key_browserConsole" key="&browserConsoleCmd.commandkey;" command="Tools:BrowserConsole" modifiers="accel,shift"/>
<key id="key_devToolbox" keycode="VK_F12" keytext="F12" command="Tools:DevToolbox"/>
<key id="key_devToolbar" keycode="&devToolbar.keycode;" modifiers="shift"
keytext="&devToolbar.keytext;" command="Tools:DevToolbarFocus"/>
<key id="key_responsiveUI" key="&responsiveDesignTool.commandkey;" command="Tools:ResponsiveUI"
#ifdef XP_MACOSX
modifiers="accel,alt"
#else
modifiers="accel,shift"
#endif
/>
<key id="key_scratchpad" keycode="&scratchpad.keycode;" modifiers="shift"
keytext="&scratchpad.keytext;" command="Tools:Scratchpad"/>
#endif
<key id="openFileKb" key="&openFileCmd.commandkey;" command="Browser:OpenFile" modifiers="accel"/>
<key id="key_savePage" key="&savePageCmd.commandkey;" command="Browser:SavePage" modifiers="accel"/>
<key id="printKb" key="&printCmd.commandkey;" command="cmd_print" modifiers="accel"/>
<key id="key_close" key="&closeCmd.key;" command="cmd_close" modifiers="accel"/>
<key id="key_closeWindow" key="&closeCmd.key;" command="cmd_closeWindow" modifiers="accel,shift"/>
<key id="key_undo"
key="&undoCmd.key;"
modifiers="accel"/>
#ifdef XP_UNIX
<key id="key_redo" key="&undoCmd.key;" modifiers="accel,shift"/>
#else
<key id="key_redo" key="&redoCmd.key;" modifiers="accel"/>
#endif
<key id="key_cut"
key="&cutCmd.key;"
modifiers="accel"/>
<key id="key_copy"
key="&copyCmd.key;"
modifiers="accel"/>
<key id="key_paste"
key="&pasteCmd.key;"
modifiers="accel"/>
<key id="key_delete" keycode="VK_DELETE" command="cmd_delete"/>
<key id="key_selectAll" key="&selectAllCmd.key;" modifiers="accel"/>
<key keycode="VK_BACK" command="cmd_handleBackspace"/>
<key keycode="VK_BACK" command="cmd_handleShiftBackspace" modifiers="shift"/>
#ifndef XP_MACOSX
<key id="goBackKb" keycode="VK_LEFT" command="Browser:Back" modifiers="alt"/>
<key id="goForwardKb" keycode="VK_RIGHT" command="Browser:Forward" modifiers="alt"/>
#else
<key id="goBackKb" keycode="VK_LEFT" command="Browser:Back" modifiers="accel" />
<key id="goForwardKb" keycode="VK_RIGHT" command="Browser:Forward" modifiers="accel" />
#endif
#ifdef XP_UNIX
<key id="goBackKb2" key="&goBackCmd.commandKey;" command="Browser:Back" modifiers="accel"/>
<key id="goForwardKb2" key="&goForwardCmd.commandKey;" command="Browser:Forward" modifiers="accel"/>
#endif
<key id="goHome" keycode="VK_HOME" command="Browser:Home" modifiers="alt"/>
<key keycode="VK_F5" command="Browser:Reload"/>
#ifndef XP_MACOSX
<key id="showAllHistoryKb" key="&showAllHistoryCmd.commandkey;" command="Browser:ShowAllHistory" modifiers="accel,shift"/>
<key keycode="VK_F5" command="Browser:ReloadSkipCache" modifiers="accel"/>
<key keycode="VK_F6" command="Browser:FocusNextFrame"/>
<key keycode="VK_F6" command="Browser:FocusNextFrame" modifiers="shift"/>
<key id="key_fullScreen" keycode="VK_F11" command="View:FullScreen"/>
#else
<key id="key_fullScreen" key="&fullScreenCmd.macCommandKey;" command="View:FullScreen" modifiers="accel,control"/>
<key id="key_fullScreen_old" key="&fullScreenCmd.macCommandKey;" command="View:FullScreen" modifiers="accel,shift"/>
<key keycode="VK_F11" command="View:FullScreen"/>
#endif
<key key="&reloadCmd.commandkey;" command="Browser:Reload" modifiers="accel" id="key_reload"/>
<key key="&reloadCmd.commandkey;" command="Browser:ReloadSkipCache" modifiers="accel,shift"/>
<key id="key_viewSource" key="&pageSourceCmd.commandkey;" command="View:PageSource" modifiers="accel"/>
#ifndef XP_WIN
<key id="key_viewInfo" key="&pageInfoCmd.commandkey;" command="View:PageInfo" modifiers="accel"/>
#endif
<key id="key_find" key="&findOnCmd.commandkey;" command="cmd_find" modifiers="accel"/>
<key id="key_findAgain" key="&findAgainCmd.commandkey;" command="cmd_findAgain" modifiers="accel"/>
<key id="key_findPrevious" key="&findAgainCmd.commandkey;" command="cmd_findPrevious" modifiers="accel,shift"/>
<key keycode="&findAgainCmd.commandkey2;" command="cmd_findAgain"/>
<key keycode="&findAgainCmd.commandkey2;" command="cmd_findPrevious" modifiers="shift"/>
<key id="addBookmarkAsKb" key="&bookmarkThisPageCmd.commandkey;" command="Browser:AddBookmarkAs" modifiers="accel"/>
# Accel+Shift+A-F are reserved on GTK
#ifndef MOZ_WIDGET_GTK
<key id="bookmarkAllTabsKb" key="&bookmarkThisPageCmd.commandkey;" oncommand="PlacesCommandHook.bookmarkCurrentPages();" modifiers="accel,shift"/>
<key id="manBookmarkKb" key="&bookmarksCmd.commandkey;" command="Browser:ShowAllBookmarks" modifiers="accel,shift"/>
#else
<key id="manBookmarkKb" key="&bookmarksGtkCmd.commandkey;" command="Browser:ShowAllBookmarks" modifiers="accel,shift"/>
#endif
<key id="viewBookmarksSidebarKb" key="&bookmarksCmd.commandkey;" command="viewBookmarksSidebar" modifiers="accel"/>
#ifdef XP_WIN
# Cmd+I is conventially mapped to Info on MacOS X, thus it should not be
# overridden for other purposes there.
<key id="viewBookmarksSidebarWinKb" key="&bookmarksWinCmd.commandkey;" command="viewBookmarksSidebar" modifiers="accel"/>
#endif
# Navigation cancel keys: Esc performs a cancel on loading (i.e.: stop button equivalent)
# Shift-Esc (and similar Shift-modified stop on Mac) performs a "superstop": this halts all
# networking requests, XHR, animated gifs, etc.
<key id="key_stop" keycode="VK_ESCAPE" command="Browser:Stop"/>
<key id="key_stop_all" keycode="VK_ESCAPE" modifiers="shift" oncommand="BrowserStop();"/>
#ifdef XP_MACOSX
<key id="key_stop_mac" modifiers="accel" key="&stopCmd.macCommandKey;" command="Browser:Stop"/>
<key id="key_stop_all_mac" modifiers="accel,shift" key="&stopCmd.macCommandKey;" oncommand="BrowserStop();"/>
#endif
<key id="key_gotoHistory"
key="&historySidebarCmd.commandKey;"
#ifdef XP_MACOSX
modifiers="accel,shift"
#else
modifiers="accel"
#endif
command="viewHistorySidebar"/>
<key id="key_fullZoomReduce" key="&fullZoomReduceCmd.commandkey;" command="cmd_fullZoomReduce" modifiers="accel"/>
<key key="&fullZoomReduceCmd.commandkey2;" command="cmd_fullZoomReduce" modifiers="accel"/>
<key id="key_fullZoomEnlarge" key="&fullZoomEnlargeCmd.commandkey;" command="cmd_fullZoomEnlarge" modifiers="accel"/>
<key key="&fullZoomEnlargeCmd.commandkey2;" command="cmd_fullZoomEnlarge" modifiers="accel"/>
<key key="&fullZoomEnlargeCmd.commandkey3;" command="cmd_fullZoomEnlarge" modifiers="accel"/>
<key id="key_fullZoomReset" key="&fullZoomResetCmd.commandkey;" command="cmd_fullZoomReset" modifiers="accel"/>
<key key="&fullZoomResetCmd.commandkey2;" command="cmd_fullZoomReset" modifiers="accel"/>
<key id="key_showAllTabs" command="Browser:ShowAllTabs" keycode="VK_TAB" modifiers="control,shift"/>
<key id="key_switchTextDirection" key="&bidiSwitchTextDirectionItem.commandkey;" command="cmd_switchTextDirection" modifiers="accel,shift" />
<key id="key_privatebrowsing" command="Tools:PrivateBrowsing" key="&privateBrowsingCmd.commandkey;" modifiers="accel,shift"/>
<key id="key_sanitize" command="Tools:Sanitize" keycode="VK_DELETE" modifiers="accel,shift"/>
#ifdef XP_MACOSX
<key id="key_sanitize_mac" command="Tools:Sanitize" keycode="VK_BACK" modifiers="accel,shift"/>
#endif
#ifdef XP_UNIX
<key id="key_quitApplication" key="&quitApplicationCmdUnix.key;" command="cmd_quitApplication" modifiers="accel"/>
#endif
#ifdef FULL_BROWSER_WINDOW
<key id="key_undoCloseTab" command="History:UndoCloseTab" key="&tabCmd.commandkey;" modifiers="accel,shift"/>
#endif
<key id="key_undoCloseWindow" command="History:UndoCloseWindow" key="&newNavigatorCmd.key;" modifiers="accel,shift"/>
#ifdef XP_GNOME
#define NUM_SELECT_TAB_MODIFIER alt
#else
#define NUM_SELECT_TAB_MODIFIER accel
#endif
#expand <key id="key_selectTab1" oncommand="gBrowser.selectTabAtIndex(0, event);" key="1" modifiers="__NUM_SELECT_TAB_MODIFIER__"/>
#expand <key id="key_selectTab2" oncommand="gBrowser.selectTabAtIndex(1, event);" key="2" modifiers="__NUM_SELECT_TAB_MODIFIER__"/>
#expand <key id="key_selectTab3" oncommand="gBrowser.selectTabAtIndex(2, event);" key="3" modifiers="__NUM_SELECT_TAB_MODIFIER__"/>
#expand <key id="key_selectTab4" oncommand="gBrowser.selectTabAtIndex(3, event);" key="4" modifiers="__NUM_SELECT_TAB_MODIFIER__"/>
#expand <key id="key_selectTab5" oncommand="gBrowser.selectTabAtIndex(4, event);" key="5" modifiers="__NUM_SELECT_TAB_MODIFIER__"/>
#expand <key id="key_selectTab6" oncommand="gBrowser.selectTabAtIndex(5, event);" key="6" modifiers="__NUM_SELECT_TAB_MODIFIER__"/>
#expand <key id="key_selectTab7" oncommand="gBrowser.selectTabAtIndex(6, event);" key="7" modifiers="__NUM_SELECT_TAB_MODIFIER__"/>
#expand <key id="key_selectTab8" oncommand="gBrowser.selectTabAtIndex(7, event);" key="8" modifiers="__NUM_SELECT_TAB_MODIFIER__"/>
#expand <key id="key_selectLastTab" oncommand="gBrowser.selectTabAtIndex(-1, event);" key="9" modifiers="__NUM_SELECT_TAB_MODIFIER__"/>
<key id="key_toggleAddonBar" command="Browser:ToggleAddonBar" key="&toggleAddonBarCmd.key;" modifiers="accel"/>
</keyset>
# Used by baseMenuOverlay
#ifdef XP_MACOSX
<commandset id="baseMenuCommandSet" />
#endif
<keyset id="baseMenuKeyset" />

View file

@ -0,0 +1,470 @@
# 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/.
// gSyncUI handles updating the tools menu
let gSyncUI = {
_obs: ["weave:service:sync:start",
"weave:service:sync:delayed",
"weave:service:quota:remaining",
"weave:service:setup-complete",
"weave:service:login:start",
"weave:service:login:finish",
"weave:service:logout:finish",
"weave:service:start-over",
"weave:ui:login:error",
"weave:ui:sync:error",
"weave:ui:sync:finish",
"weave:ui:clear-error",
],
_unloaded: false,
init: function SUI_init() {
// Proceed to set up the UI if Sync has already started up.
// Otherwise we'll do it when Sync is firing up.
let xps = Components.classes["@mozilla.org/weave/service;1"]
.getService(Components.interfaces.nsISupports)
.wrappedJSObject;
if (xps.ready) {
this.initUI();
return;
}
Services.obs.addObserver(this, "weave:service:ready", true);
// Remove the observer if the window is closed before the observer
// was triggered.
window.addEventListener("unload", function onUnload() {
gSyncUI._unloaded = true;
window.removeEventListener("unload", onUnload, false);
Services.obs.removeObserver(gSyncUI, "weave:service:ready");
if (Weave.Status.ready) {
gSyncUI._obs.forEach(function(topic) {
Services.obs.removeObserver(gSyncUI, topic);
});
}
}, false);
},
initUI: function SUI_initUI() {
// If this is a browser window?
if (gBrowser) {
this._obs.push("weave:notification:added");
}
this._obs.forEach(function(topic) {
Services.obs.addObserver(this, topic, true);
}, this);
if (gBrowser && Weave.Notifications.notifications.length) {
this.initNotifications();
}
this.updateUI();
},
initNotifications: function SUI_initNotifications() {
const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
let notificationbox = document.createElementNS(XULNS, "notificationbox");
notificationbox.id = "sync-notifications";
notificationbox.setAttribute("flex", "1");
let bottombox = document.getElementById("browser-bottombox");
bottombox.insertBefore(notificationbox, bottombox.firstChild);
// Force a style flush to ensure that our binding is attached.
notificationbox.clientTop;
// notificationbox will listen to observers from now on.
Services.obs.removeObserver(this, "weave:notification:added");
},
_wasDelayed: false,
_needsSetup: function SUI__needsSetup() {
let firstSync = "";
try {
firstSync = Services.prefs.getCharPref("services.sync.firstSync");
} catch (e) { }
return Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED ||
firstSync == "notReady";
},
updateUI: function SUI_updateUI() {
let needsSetup = this._needsSetup();
document.getElementById("sync-setup-state").hidden = !needsSetup;
document.getElementById("sync-syncnow-state").hidden = needsSetup;
if (!gBrowser)
return;
let button = document.getElementById("sync-button");
if (!button)
return;
button.removeAttribute("status");
this._updateLastSyncTime();
if (needsSetup)
button.removeAttribute("tooltiptext");
},
// Functions called by observers
onActivityStart: function SUI_onActivityStart() {
if (!gBrowser)
return;
let button = document.getElementById("sync-button");
if (!button)
return;
button.setAttribute("status", "active");
},
onSyncDelay: function SUI_onSyncDelay() {
// basically, we want to just inform users that stuff is going to take a while
let title = this._stringBundle.GetStringFromName("error.sync.no_node_found.title");
let description = this._stringBundle.GetStringFromName("error.sync.no_node_found");
let buttons = [new Weave.NotificationButton(
this._stringBundle.GetStringFromName("error.sync.serverStatusButton.label"),
this._stringBundle.GetStringFromName("error.sync.serverStatusButton.accesskey"),
function() { gSyncUI.openServerStatus(); return true; }
)];
let notification = new Weave.Notification(
title, description, null, Weave.Notifications.PRIORITY_INFO, buttons);
Weave.Notifications.replaceTitle(notification);
this._wasDelayed = true;
},
onLoginFinish: function SUI_onLoginFinish() {
// Clear out any login failure notifications
let title = this._stringBundle.GetStringFromName("error.login.title");
this.clearError(title);
},
onSetupComplete: function SUI_onSetupComplete() {
this.onLoginFinish();
},
onLoginError: function SUI_onLoginError() {
// if login fails, any other notifications are essentially moot
Weave.Notifications.removeAll();
// if we haven't set up the client, don't show errors
if (this._needsSetup()) {
this.updateUI();
return;
}
let title = this._stringBundle.GetStringFromName("error.login.title");
let description;
if (Weave.Status.sync == Weave.PROLONGED_SYNC_FAILURE) {
// Convert to days
let lastSync =
Services.prefs.getIntPref("services.sync.errorhandler.networkFailureReportTimeout") / 86400;
description =
this._stringBundle.formatStringFromName("error.sync.prolonged_failure", [lastSync], 1);
} else {
let reason = Weave.Utils.getErrorString(Weave.Status.login);
description =
this._stringBundle.formatStringFromName("error.sync.description", [reason], 1);
}
let buttons = [];
buttons.push(new Weave.NotificationButton(
this._stringBundle.GetStringFromName("error.login.prefs.label"),
this._stringBundle.GetStringFromName("error.login.prefs.accesskey"),
function() { gSyncUI.openPrefs(); return true; }
));
let notification = new Weave.Notification(title, description, null,
Weave.Notifications.PRIORITY_WARNING, buttons);
Weave.Notifications.replaceTitle(notification);
this.updateUI();
},
onLogout: function SUI_onLogout() {
this.updateUI();
},
onStartOver: function SUI_onStartOver() {
this.clearError();
},
onQuotaNotice: function onQuotaNotice(subject, data) {
let title = this._stringBundle.GetStringFromName("warning.sync.quota.label");
let description = this._stringBundle.GetStringFromName("warning.sync.quota.description");
let buttons = [];
buttons.push(new Weave.NotificationButton(
this._stringBundle.GetStringFromName("error.sync.viewQuotaButton.label"),
this._stringBundle.GetStringFromName("error.sync.viewQuotaButton.accesskey"),
function() { gSyncUI.openQuotaDialog(); return true; }
));
let notification = new Weave.Notification(
title, description, null, Weave.Notifications.PRIORITY_WARNING, buttons);
Weave.Notifications.replaceTitle(notification);
},
openServerStatus: function () {
let statusURL = Services.prefs.getCharPref("services.sync.statusURL");
window.openUILinkIn(statusURL, "tab");
},
// Commands
doSync: function SUI_doSync() {
setTimeout(function() Weave.Service.errorHandler.syncAndReportErrors(), 0);
},
handleToolbarButton: function SUI_handleStatusbarButton() {
if (this._needsSetup())
this.openSetup();
else
this.doSync();
},
//XXXzpao should be part of syncCommon.js - which we might want to make a module...
// To be fixed in a followup (bug 583366)
/**
* Invoke the Sync setup wizard.
*
* @param wizardType
* Indicates type of wizard to launch:
* null -- regular set up wizard
* "pair" -- pair a device first
* "reset" -- reset sync
*/
openSetup: function SUI_openSetup(wizardType) {
let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
if (win)
win.focus();
else {
window.openDialog("chrome://browser/content/sync/setup.xul",
"weaveSetup", "centerscreen,chrome,resizable=no",
wizardType);
}
},
openAddDevice: function () {
if (!Weave.Utils.ensureMPUnlocked())
return;
let win = Services.wm.getMostRecentWindow("Sync:AddDevice");
if (win)
win.focus();
else
window.openDialog("chrome://browser/content/sync/addDevice.xul",
"syncAddDevice", "centerscreen,chrome,resizable=no");
},
openQuotaDialog: function SUI_openQuotaDialog() {
let win = Services.wm.getMostRecentWindow("Sync:ViewQuota");
if (win)
win.focus();
else
Services.ww.activeWindow.openDialog(
"chrome://browser/content/sync/quota.xul", "",
"centerscreen,chrome,dialog,modal");
},
openPrefs: function SUI_openPrefs() {
openPreferences("paneSync");
},
// Helpers
_updateLastSyncTime: function SUI__updateLastSyncTime() {
if (!gBrowser)
return;
let syncButton = document.getElementById("sync-button");
if (!syncButton)
return;
let lastSync;
try {
lastSync = Services.prefs.getCharPref("services.sync.lastSync");
}
catch (e) { };
if (!lastSync || this._needsSetup()) {
syncButton.removeAttribute("tooltiptext");
return;
}
// Show the day-of-week and time (HH:MM) of last sync
let lastSyncDate = new Date(lastSync).toLocaleFormat("%a %H:%M");
let lastSyncLabel =
this._stringBundle.formatStringFromName("lastSync2.label", [lastSyncDate], 1);
syncButton.setAttribute("tooltiptext", lastSyncLabel);
},
clearError: function SUI_clearError(errorString) {
Weave.Notifications.removeAll(errorString);
this.updateUI();
},
onSyncFinish: function SUI_onSyncFinish() {
let title = this._stringBundle.GetStringFromName("error.sync.title");
// Clear out sync failures on a successful sync
this.clearError(title);
if (this._wasDelayed && Weave.Status.sync != Weave.NO_SYNC_NODE_FOUND) {
title = this._stringBundle.GetStringFromName("error.sync.no_node_found.title");
this.clearError(title);
this._wasDelayed = false;
}
},
onSyncError: function SUI_onSyncError() {
let title = this._stringBundle.GetStringFromName("error.sync.title");
if (Weave.Status.login != Weave.LOGIN_SUCCEEDED) {
this.onLoginError();
return;
}
let description;
if (Weave.Status.sync == Weave.PROLONGED_SYNC_FAILURE) {
// Convert to days
let lastSync =
Services.prefs.getIntPref("services.sync.errorhandler.networkFailureReportTimeout") / 86400;
description =
this._stringBundle.formatStringFromName("error.sync.prolonged_failure", [lastSync], 1);
} else {
let error = Weave.Utils.getErrorString(Weave.Status.sync);
description =
this._stringBundle.formatStringFromName("error.sync.description", [error], 1);
}
let priority = Weave.Notifications.PRIORITY_WARNING;
let buttons = [];
// Check if the client is outdated in some way
let outdated = Weave.Status.sync == Weave.VERSION_OUT_OF_DATE;
for (let [engine, reason] in Iterator(Weave.Status.engines))
outdated = outdated || reason == Weave.VERSION_OUT_OF_DATE;
if (outdated) {
description = this._stringBundle.GetStringFromName(
"error.sync.needUpdate.description");
buttons.push(new Weave.NotificationButton(
this._stringBundle.GetStringFromName("error.sync.needUpdate.label"),
this._stringBundle.GetStringFromName("error.sync.needUpdate.accesskey"),
function() {
window.openUILinkIn(Services.prefs.getCharPref("services.sync.outdated.url"), "tab");
return true;
}
));
}
else if (Weave.Status.sync == Weave.OVER_QUOTA) {
description = this._stringBundle.GetStringFromName(
"error.sync.quota.description");
buttons.push(new Weave.NotificationButton(
this._stringBundle.GetStringFromName(
"error.sync.viewQuotaButton.label"),
this._stringBundle.GetStringFromName(
"error.sync.viewQuotaButton.accesskey"),
function() { gSyncUI.openQuotaDialog(); return true; } )
);
}
else if (Weave.Status.enforceBackoff) {
priority = Weave.Notifications.PRIORITY_INFO;
buttons.push(new Weave.NotificationButton(
this._stringBundle.GetStringFromName("error.sync.serverStatusButton.label"),
this._stringBundle.GetStringFromName("error.sync.serverStatusButton.accesskey"),
function() { gSyncUI.openServerStatus(); return true; }
));
}
else {
priority = Weave.Notifications.PRIORITY_INFO;
buttons.push(new Weave.NotificationButton(
this._stringBundle.GetStringFromName("error.sync.tryAgainButton.label"),
this._stringBundle.GetStringFromName("error.sync.tryAgainButton.accesskey"),
function() { gSyncUI.doSync(); return true; }
));
}
let notification =
new Weave.Notification(title, description, null, priority, buttons);
Weave.Notifications.replaceTitle(notification);
if (this._wasDelayed && Weave.Status.sync != Weave.NO_SYNC_NODE_FOUND) {
title = this._stringBundle.GetStringFromName("error.sync.no_node_found.title");
Weave.Notifications.removeAll(title);
this._wasDelayed = false;
}
this.updateUI();
},
observe: function SUI_observe(subject, topic, data) {
if (this._unloaded) {
Cu.reportError("SyncUI observer called after unload: " + topic);
return;
}
switch (topic) {
case "weave:service:sync:start":
this.onActivityStart();
break;
case "weave:ui:sync:finish":
this.onSyncFinish();
break;
case "weave:ui:sync:error":
this.onSyncError();
break;
case "weave:service:sync:delayed":
this.onSyncDelay();
break;
case "weave:service:quota:remaining":
this.onQuotaNotice();
break;
case "weave:service:setup-complete":
this.onSetupComplete();
break;
case "weave:service:login:start":
this.onActivityStart();
break;
case "weave:service:login:finish":
this.onLoginFinish();
break;
case "weave:ui:login:error":
this.onLoginError();
break;
case "weave:service:logout:finish":
this.onLogout();
break;
case "weave:service:start-over":
this.onStartOver();
break;
case "weave:service:ready":
this.initUI();
break;
case "weave:notification:added":
this.initNotifications();
break;
case "weave:ui:clear-error":
this.clearError();
break;
}
},
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIObserver,
Ci.nsISupportsWeakReference
])
};
XPCOMUtils.defineLazyGetter(gSyncUI, "_stringBundle", function() {
//XXXzpao these strings should probably be moved from /services to /browser... (bug 583381)
// but for now just make it work
return Cc["@mozilla.org/intl/stringbundle;1"].
getService(Ci.nsIStringBundleService).
createBundle("chrome://weave/locale/services/sync.properties");
});

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,75 @@
<?xml version="1.0"?>
# -*- Mode: HTML -*-
# 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/.
<bindings id="tabPreviews"
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="ctrlTab-preview" extends="chrome://global/content/bindings/button.xml#button-base">
<content pack="center">
<xul:stack>
<xul:vbox class="ctrlTab-preview-inner" align="center" pack="center"
xbl:inherits="width=canvaswidth">
<xul:hbox class="tabPreview-canvas" xbl:inherits="style=canvasstyle">
<children/>
</xul:hbox>
<xul:label xbl:inherits="value=label,crop" class="plain"/>
</xul:vbox>
<xul:hbox class="ctrlTab-favicon-container" xbl:inherits="hidden=noicon">
<xul:image class="ctrlTab-favicon" xbl:inherits="src=image"/>
</xul:hbox>
</xul:stack>
</content>
<handlers>
<handler event="mouseover" action="ctrlTab._mouseOverFocus(this);"/>
<handler event="command" action="ctrlTab.pick(this);"/>
<handler event="click" button="1" action="ctrlTab.remove(this);"/>
#ifdef XP_MACOSX
# Control+click is a right click on OS X
<handler event="click" button="2" action="ctrlTab.pick(this);"/>
#endif
</handlers>
</binding>
<binding id="allTabs-preview" extends="chrome://global/content/bindings/button.xml#button-base">
<content pack="center" align="center">
<xul:stack>
<xul:vbox class="allTabs-preview-inner" align="center" pack="center">
<xul:hbox class="tabPreview-canvas" xbl:inherits="style=canvasstyle">
<children/>
</xul:hbox>
<xul:label flex="1" xbl:inherits="value=label,crop" class="allTabs-preview-label plain"/>
</xul:vbox>
<xul:hbox class="allTabs-favicon-container">
<xul:image class="allTabs-favicon" xbl:inherits="src=image"/>
</xul:hbox>
</xul:stack>
</content>
<handlers>
<handler event="command" action="allTabs.pick(this);"/>
<handler event="click" button="1" action="gBrowser.removeTab(this._tab);"/>
<handler event="dragstart"><![CDATA[
event.dataTransfer.mozSetDataAt("application/x-moz-node", this._tab, 0);
]]></handler>
<handler event="dragover"><![CDATA[
let tab = event.dataTransfer.mozGetDataAt("application/x-moz-node", 0);
if (tab && tab.parentNode == gBrowser.tabContainer)
event.preventDefault();
]]></handler>
<handler event="drop"><![CDATA[
let tab = event.dataTransfer.mozGetDataAt("application/x-moz-node", 0);
if (tab && tab.parentNode == gBrowser.tabContainer) {
let newIndex = Array.indexOf(gBrowser.tabs, this._tab);
gBrowser.moveTabTo(tab, newIndex);
}
]]></handler>
</handlers>
</binding>
</bindings>

View file

@ -0,0 +1,198 @@
#ifdef 0
/* 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/. */
#endif
/**
* Keeps thumbnails of open web pages up-to-date.
*/
let gBrowserThumbnails = {
/**
* Pref that controls whether we can store SSL content on disk
*/
PREF_DISK_CACHE_SSL: "browser.cache.disk_cache_ssl",
_captureDelayMS: 1000,
/**
* Used to keep track of disk_cache_ssl preference
*/
_sslDiskCacheEnabled: null,
/**
* Map of capture() timeouts assigned to their browsers.
*/
_timeouts: null,
/**
* List of tab events we want to listen for.
*/
_tabEvents: ["TabClose", "TabSelect"],
init: function Thumbnails_init() {
// Bug 863512 - Make page thumbnails work in electrolysis
if (gMultiProcessBrowser)
return;
try {
if (Services.prefs.getBoolPref("browser.pagethumbnails.capturing_disabled"))
return;
} catch (e) {}
PageThumbs.addExpirationFilter(this);
gBrowser.addTabsProgressListener(this);
Services.prefs.addObserver(this.PREF_DISK_CACHE_SSL, this, false);
this._sslDiskCacheEnabled =
Services.prefs.getBoolPref(this.PREF_DISK_CACHE_SSL);
this._tabEvents.forEach(function (aEvent) {
gBrowser.tabContainer.addEventListener(aEvent, this, false);
}, this);
this._timeouts = new WeakMap();
},
uninit: function Thumbnails_uninit() {
// Bug 863512 - Make page thumbnails work in electrolysis
if (gMultiProcessBrowser)
return;
PageThumbs.removeExpirationFilter(this);
gBrowser.removeTabsProgressListener(this);
Services.prefs.removeObserver(this.PREF_DISK_CACHE_SSL, this);
this._tabEvents.forEach(function (aEvent) {
gBrowser.tabContainer.removeEventListener(aEvent, this, false);
}, this);
},
handleEvent: function Thumbnails_handleEvent(aEvent) {
switch (aEvent.type) {
case "scroll":
let browser = aEvent.currentTarget;
if (this._timeouts.has(browser))
this._delayedCapture(browser);
break;
case "TabSelect":
this._delayedCapture(aEvent.target.linkedBrowser);
break;
case "TabClose": {
this._clearTimeout(aEvent.target.linkedBrowser);
break;
}
}
},
observe: function Thumbnails_observe() {
this._sslDiskCacheEnabled =
Services.prefs.getBoolPref(this.PREF_DISK_CACHE_SSL);
},
filterForThumbnailExpiration:
function Thumbnails_filterForThumbnailExpiration(aCallback) {
aCallback([browser.currentURI.spec for (browser of gBrowser.browsers)]);
},
/**
* State change progress listener for all tabs.
*/
onStateChange: function Thumbnails_onStateChange(aBrowser, aWebProgress,
aRequest, aStateFlags, aStatus) {
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK)
this._delayedCapture(aBrowser);
},
_capture: function Thumbnails_capture(aBrowser) {
if (this._shouldCapture(aBrowser))
PageThumbs.captureAndStore(aBrowser);
},
_delayedCapture: function Thumbnails_delayedCapture(aBrowser) {
if (this._timeouts.has(aBrowser))
clearTimeout(this._timeouts.get(aBrowser));
else
aBrowser.addEventListener("scroll", this, true);
let timeout = setTimeout(function () {
this._clearTimeout(aBrowser);
this._capture(aBrowser);
}.bind(this), this._captureDelayMS);
this._timeouts.set(aBrowser, timeout);
},
_shouldCapture: function Thumbnails_shouldCapture(aBrowser) {
// Capture only if it's the currently selected tab.
if (aBrowser != gBrowser.selectedBrowser)
return false;
// Don't capture in per-window private browsing mode.
if (PrivateBrowsingUtils.isWindowPrivate(window))
return false;
let doc = aBrowser.contentDocument;
// FIXME Bug 720575 - Don't capture thumbnails for SVG or XML documents as
// that currently regresses Talos SVG tests.
if (doc instanceof SVGDocument || doc instanceof XMLDocument)
return false;
// There's no point in taking screenshot of loading pages.
if (aBrowser.docShell.busyFlags != Ci.nsIDocShell.BUSY_FLAGS_NONE)
return false;
// Don't take screenshots of about: pages.
if (aBrowser.currentURI.schemeIs("about"))
return false;
let channel = aBrowser.docShell.currentDocumentChannel;
// No valid document channel. We shouldn't take a screenshot.
if (!channel)
return false;
// Don't take screenshots of internally redirecting about: pages.
// This includes error pages.
let uri = channel.originalURI;
if (uri.schemeIs("about"))
return false;
let httpChannel;
try {
httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
} catch (e) { /* Not an HTTP channel. */ }
if (httpChannel) {
// Continue only if we have a 2xx status code.
try {
if (Math.floor(httpChannel.responseStatus / 100) != 2)
return false;
} catch (e) {
// Can't get response information from the httpChannel
// because mResponseHead is not available.
return false;
}
// Cache-Control: no-store.
if (httpChannel.isNoStoreResponse())
return false;
// Don't capture HTTPS pages unless the user explicitly enabled it.
if (uri.schemeIs("https") && !this._sslDiskCacheEnabled)
return false;
}
return true;
},
_clearTimeout: function Thumbnails_clearTimeout(aBrowser) {
if (this._timeouts.has(aBrowser)) {
aBrowser.removeEventListener("scroll", this, false);
clearTimeout(this._timeouts.get(aBrowser));
this._timeouts.delete(aBrowser);
}
}
};

View file

@ -0,0 +1,204 @@
/* 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/. */
#main-window::after {
content: attr(title);
line-height: 50px;
max-height: 50px;
overflow: -moz-hidden-unscrollable;
pointer-events: none;
position: fixed;
word-wrap: break-word;
-moz-hyphens: auto;
color: CaptionText;
font-weight: bold;
text-align: left;
}
#main-window:-moz-window-inactive::after {
color: InactiveCaptionText;
}
/* Win10 doesn't respond to inactive caption, so dim it instead */
@media (-moz-os-version: windows-win10) {
#main-window:-moz-window-inactive::after {
opacity: 0.5;
}
}
/* Hide in fullscreen/TiT mode */
#main-window[inFullscreen="true"]::after,
#main-window[sizemode="maximized"][tabsintitlebar="true"]::after,
#main-window:not([chromemargin])::after {
opacity: 0 !important;
}
#main-window::after {
padding: 0 132px; /* AppMenu button/wincontrols width offset */
left: 0;
right: 0;
}
#main-window[privatebrowsingmode=temporary]::after {
padding: 0px 132px 0px 152px; /* AppMenu button width offset for PB mode */
}
#main-window[sizemode="normal"]::after {
left: -12px;
right: -12px;
}
/* Lightweight Themes */
#main-window:-moz-lwtheme::after {
color: inherit;
text-shadow: inherit;
}
/* Windows Classic theme */
@media all and (-moz-windows-classic) {
#main-window::after {
top: -13px;
text-shadow: none !important;
background-position: 2px 18px;
}
}
/* Windows Aero (Vista, non-glass 7/8) */
@media all and (-moz-windows-theme: aero) {
#main-window::after {
top: -11px;
font-weight: normal;
text-shadow: none;
background-position: 2px 17px;
}
#main-window[sizemode="maximized"]::after {
top: -7px;
}
}
/* Windows Aero Glass */
@media (-moz-windows-glass) {
#main-window::after {
top: -13px;
color: black;
text-shadow: rgba(255,255,255,.6) 7px -1px 12px,
rgba(255,255,255,.6) 6px -1px 13px,
rgba(255,255,255,.9) 5px -1px 14px,
rgba(255,255,255,.6) -7px -1px 12px,
rgba(255,255,255,.6) -6px -1px 13px,
rgba(255,255,255,.9) -5px -1px 14px;
z-index: -99999;
background-position: 2px 18px;
font-weight: bold;
}
#main-window[sizemode="maximized"]::after {
top: -7px;
}
#main-window:-moz-window-inactive::after {
opacity: .9;
color: black;
text-shadow: rgba(255,255,255,.7) 7px -1px 12px,
rgba(255,255,255,.5) 6px -1px 13px,
rgba(255,255,255,.5) 5px -1px 14px,
rgba(255,255,255,.7) -7px -1px 12px,
rgba(255,255,255,.5) -6px -1px 13px,
rgba(255,255,255,.5) -5px -1px 14px;
}
}
/* Generic other themes */
@media all and (-moz-windows-theme: generic) {
#main-window::after {
font-family: trebuchet MS;
font-size: 13px;
text-shadow: 1px 1px rgba(0, 0, 0, .2);
top: -9px;
background-position: 2px 16px;
}
#main-window:-moz-window-inactive::after {
text-shadow: none;
}
}
/* Compositor style for Win 8/10 */
@media all and (-moz-windows-compositor) {
@media not all and (-moz-windows-glass) {
#main-window::after {
background-position: 4px 17px;
top: -13px;
}
@media (-moz-os-version: windows-win8) {
#main-window::after {
font-size: 15px;
text-align: center;
}
#main-window[darkwindowframe="true"]:not(:-moz-window-inactive):not(:-moz-lwtheme)::after {
/* Dark window frame/accent color on Win 8 */
color: white;
}
}
@media (-moz-os-version: windows-win10) {
#main-window::after {
text-align: left;
}
@media (-moz-windows-accent-color-applies: 0) {
#main-window:not(:-moz-window-inactive):not(:-moz-lwtheme)::after {
/* Default Windows 10 styling is white - apply black text styling */
color: black;
}
}
@media (-moz-windows-accent-color-applies) {
#main-window:not(:-moz-window-inactive):not(:-moz-lwtheme)::after {
/* Accent color is applied - use the associated text styling */
color: -moz-win-accentcolortext;
}
}
}
#main-window[sizemode="maximized"]::after {
top: -5px;
}
}
}
/* Hide for small windows */
@media not all and (min-width: 320px) {
#main-window::after {
opacity: 0 !important;
}
}

View file

@ -0,0 +1,55 @@
# -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# 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 WebrtcIndicator = {
init: function () {
let temp = {};
Cu.import("resource:///modules/webrtcUI.jsm", temp);
this.UIModule = temp.webrtcUI;
this.updateButton();
},
get button() {
delete this.button;
return this.button = document.getElementById("webrtc-status-button");
},
updateButton: function () {
this.button.hidden = !this.UIModule.showGlobalIndicator;
},
fillPopup: function (aPopup) {
this._menuitemData = new WeakMap;
for (let streamData of this.UIModule.activeStreams) {
let menuitem = document.createElement("menuitem");
menuitem.setAttribute("label", streamData.uri);
menuitem.setAttribute("tooltiptext", streamData.uri);
this._menuitemData.set(menuitem, streamData);
aPopup.appendChild(menuitem);
}
},
clearPopup: function (aPopup) {
while (aPopup.lastChild)
aPopup.removeChild(aPopup.lastChild);
},
menuCommand: function (aMenuitem) {
let streamData = this._menuitemData.get(aMenuitem);
if (!streamData)
return;
let browserWindow = streamData.browser.ownerDocument.defaultView;
if (streamData.tab) {
browserWindow.gBrowser.selectedTab = streamData.tab;
} else {
streamData.browser.focus();
}
browserWindow.focus();
}
}

View file

@ -0,0 +1,693 @@
/* 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/. */
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
@namespace html url("http://www.w3.org/1999/xhtml");
searchbar {
-moz-binding: url("chrome://browser/content/search/search.xml#searchbar");
}
browser[remote="true"] {
-moz-binding: url("chrome://global/content/bindings/remote-browser.xml#remote-browser");
}
tabbrowser {
-moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser");
}
.tabbrowser-tabs {
-moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tabs");
}
#tabbrowser-tabs:not([overflow="true"]) ~ #alltabs-button,
#tabbrowser-tabs:not([overflow="true"]) + #new-tab-button,
#tabbrowser-tabs[overflow="true"] > .tabbrowser-arrowscrollbox > .tabs-newtab-button,
#TabsToolbar[currentset]:not([currentset*="tabbrowser-tabs,new-tab-button"]) > #tabbrowser-tabs > .tabbrowser-arrowscrollbox > .tabs-newtab-button,
#TabsToolbar[customizing="true"] > #tabbrowser-tabs > .tabbrowser-arrowscrollbox > .tabs-newtab-button {
visibility: collapse;
}
#alltabs-button { /* Pale Moon: Always show this button! (less jumpy UI) */
visibility: visible !important;
}
#tabbrowser-tabs:not([overflow="true"])[using-closing-tabs-spacer] ~ #alltabs-button {
visibility: hidden; /* temporary space to keep a tab's close button under the cursor */
}
.tabbrowser-tab {
-moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tab");
}
.tabbrowser-tab:not([pinned]) {
-moz-box-flex: 100;
max-width: 250px;
min-width: 100px;
width: 0;
transition: min-width 175ms ease-out,
max-width 200ms ease-out,
opacity 80ms ease-out 20ms /* hide the tab for the first 20ms of the max-width transition */;
}
.tabbrowser-tab:not([pinned]):not([fadein]) {
max-width: 0.1px;
min-width: 0.1px;
opacity: 0 !important;
transition: min-width 175ms ease-out,
max-width 200ms ease-out,
opacity 80ms ease-out 180ms /* hide the tab for the last 20ms of the max-width transition */;
}
.tab-throbber:not([fadein]):not([pinned]),
.tab-label:not([fadein]):not([pinned]),
.tab-icon-image:not([fadein]):not([pinned]),
.tab-close-button:not([fadein]):not([pinned]) {
display: none;
}
.tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[pinned] {
position: fixed !important;
display: block; /* position:fixed already does this (bug 579776), but let's be explicit */
}
.tabbrowser-tabs[movingtab] > .tabbrowser-tab[selected] {
position: relative;
z-index: 2;
pointer-events: none; /* avoid blocking dragover events on scroll buttons */
}
.tabbrowser-tabs[movingtab] > .tabbrowser-tab[fadein]:not([selected]) {
transition: transform 200ms ease-out;
}
#alltabs-popup {
-moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-alltabs-popup");
}
toolbar[printpreview="true"] {
-moz-binding: url("chrome://global/content/printPreviewBindings.xml#printpreviewtoolbar");
}
#toolbar-menubar {
-moz-box-ordinal-group: 5;
}
#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
-moz-box-ordinal-group: 50;
}
#TabsToolbar {
-moz-box-ordinal-group: 100;
}
#TabsToolbar[tabsontop="true"] {
-moz-box-ordinal-group: 10;
}
%ifdef CAN_DRAW_IN_TITLEBAR
#main-window[inFullscreen] > #titlebar,
#main-window[inFullscreen] .titlebar-placeholder,
#main-window:not([tabsintitlebar]) .titlebar-placeholder {
display: none;
}
#titlebar {
-moz-binding: url("chrome://global/content/bindings/general.xml#windowdragbox");
}
#titlebar-spacer {
pointer-events: none;
}
#main-window[tabsintitlebar] #appmenu-button-container,
#main-window[tabsintitlebar] #titlebar-buttonbox {
position: relative;
}
%endif
#main-window[inDOMFullscreen] #sidebar-box,
#main-window[inDOMFullscreen] #sidebar-splitter {
visibility: collapse;
}
.bookmarks-toolbar-customize,
#wrapper-personal-bookmarks > #personal-bookmarks > #PlacesToolbar > hbox > #PlacesToolbarItems {
display: none;
}
#wrapper-personal-bookmarks[place="toolbar"] > #personal-bookmarks > #PlacesToolbar > .bookmarks-toolbar-customize {
display: -moz-box;
}
#main-window[disablechrome] #navigator-toolbox[tabsontop="true"] > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
visibility: collapse;
}
#wrapper-urlbar-container #urlbar-container > #urlbar > toolbarbutton,
#urlbar-container:not([combined]) > #urlbar > toolbarbutton,
#urlbar-container[combined] + #reload-button + #stop-button,
#urlbar-container[combined] + #reload-button,
toolbar:not([mode="icons"]) > #urlbar-container > #urlbar > toolbarbutton,
toolbar[mode="icons"] > #urlbar-container > #urlbar > #urlbar-reload-button:not([displaystop]) + #urlbar-stop-button,
toolbar[mode="icons"] > #urlbar-container > #urlbar > #urlbar-reload-button[displaystop],
toolbar[mode="icons"] > #reload-button:not([displaystop]) + #stop-button,
toolbar[mode="icons"] > #reload-button[displaystop] {
visibility: collapse;
}
#feed-button > .toolbarbutton-menu-dropmarker {
display: none;
}
#feed-menu > .feed-menuitem:-moz-locale-dir(rtl) {
direction: rtl;
}
#main-window:-moz-lwtheme {
background-repeat: no-repeat;
background-position: top right;
}
%ifdef XP_MACOSX
#main-window[inFullscreen="true"] {
padding-top: 0; /* override drawintitlebar="true" */
}
%endif
#browser-bottombox[lwthemefooter="true"] {
background-repeat: no-repeat;
background-position: bottom left;
}
splitmenu {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#splitmenu");
}
.splitmenu-menuitem {
-moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem");
list-style-image: inherit;
-moz-image-region: inherit;
}
.splitmenu-menuitem[iconic="true"] {
-moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem-iconic");
}
.splitmenu-menu > .menu-text,
:-moz-any(.splitmenu-menu, .splitmenu-menuitem) > .menu-accel-container,
#appmenu-editmenu > .menu-text,
#appmenu-editmenu > .menu-accel-container {
display: none;
}
.menuitem-tooltip {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#menuitem-tooltip");
}
.menuitem-iconic-tooltip,
.menuitem-tooltip[type="checkbox"],
.menuitem-tooltip[type="radio"] {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#menuitem-iconic-tooltip");
}
%ifdef MENUBAR_CAN_AUTOHIDE
%ifndef CAN_DRAW_IN_TITLEBAR
#appmenu-toolbar-button > .toolbarbutton-text {
display: -moz-box;
}
%endif
#appmenu_offlineModeRecovery:not([checked=true]) {
display: none;
}
%endif
/* Hide menu elements intended for keyboard access support */
#main-menubar[openedwithkey=false] .show-only-for-keyboard {
display: none;
}
/* ::::: location bar ::::: */
#urlbar {
-moz-binding: url(chrome://browser/content/urlbarBindings.xml#urlbar);
}
.ac-url-text:-moz-locale-dir(rtl),
.ac-title:-moz-locale-dir(rtl) > description {
direction: ltr !important;
}
/* For results that are actions, their description text is shown instead of
the URL - this needs to follow the locale's direction, unlike URLs. */
panel:not([noactions]) > richlistbox > richlistitem[type~="action"]:-moz-locale-dir(rtl) > .ac-url-box {
direction: rtl;
}
panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .ac-url > .ac-action-text,
panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .ac-action-icon {
visibility: collapse;
}
panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .ac-url > .ac-url-text {
visibility: visible;
}
#urlbar:not([actiontype]) > #urlbar-display-box {
display: none;
}
#wrapper-urlbar-container > #urlbar-container > #urlbar {
-moz-user-input: disabled;
cursor: -moz-grab;
}
#PopupAutoComplete {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#browser-autocomplete-result-popup");
}
#PopupAutoCompleteRichResult {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#urlbar-rich-result-popup");
}
/* Pale Moon: Address bar: Feeds */
#ub-feed-button > .button-box > .box-inherit > .button-text,
#ub-feed-button > .button-box > .button-menu-dropmarker {
display: none;
}
#ub-feed-menu > .feed-menuitem:-moz-locale-dir(rtl) {
direction: rtl;
}
#urlbar-container[combined] > #urlbar > #urlbar-icons > #go-button,
#urlbar[pageproxystate="invalid"] > #urlbar-icons > .urlbar-icon:not(#go-button),
#urlbar[pageproxystate="valid"] > #urlbar-icons > #go-button,
#urlbar[pageproxystate="invalid"][focused="true"] > #urlbar-go-button ~ toolbarbutton,
#urlbar[pageproxystate="valid"] > #urlbar-go-button,
#urlbar:not([focused="true"]) > #urlbar-go-button {
visibility: collapse;
}
#urlbar[pageproxystate="invalid"] > #identity-box > #identity-icon-labels {
visibility: collapse;
}
#urlbar[pageproxystate="invalid"] > #identity-box {
pointer-events: none;
}
#identity-icon-labels {
max-width: 18em;
}
#identity-icon-country-label {
direction: ltr;
}
#identity-box.verifiedIdentity > #identity-icon-labels > #identity-icon-label {
-moz-margin-end: 0.25em !important;
}
#wrapper-search-container > #search-container > #searchbar > .searchbar-textbox > .autocomplete-textbox-container > .textbox-input-box > html|*.textbox-input {
visibility: hidden;
}
/* ::::: Unified Back-/Forward Button ::::: */
#back-button > .toolbarbutton-menu-dropmarker,
#forward-button > .toolbarbutton-menu-dropmarker {
display: none;
}
.unified-nav-current {
font-weight: bold;
}
toolbarbutton.bookmark-item {
max-width: 13em;
}
%ifdef MENUBAR_CAN_AUTOHIDE
#toolbar-menubar:not([autohide="true"]) ~ toolbar > #bookmarks-menu-button,
#toolbar-menubar:not([autohide="true"]) > #bookmarks-menu-button,
#toolbar-menubar:not([autohide="true"]) ~ toolbar > #history-menu-button,
#toolbar-menubar:not([autohide="true"]) > #history-menu-button {
display: none;
}
%endif
#editBMPanel_tagsSelector {
/* override default listbox width from xul.css */
width: auto;
}
menupopup[emptyplacesresult="true"] > .hide-if-empty-places-result {
display: none;
}
menuitem.spell-suggestion {
font-weight: bold;
}
#sidebar-header > .tabs-closebutton {
-moz-user-focus: normal;
}
/* apply Fitts' law to the notification bar's close button */
window[sizemode="maximized"] #content .notification-inner {
border-right: 0px !important;
}
/* Hide extension toolbars that neglected to set the proper class */
window[chromehidden~="location"][chromehidden~="toolbar"] toolbar:not(.chromeclass-menubar),
window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(#nav-bar):not(#TabsToolbar):not(#print-preview-toolbar):not(.chromeclass-menubar) {
display: none;
}
#navigator-toolbox ,
#status-bar ,
#mainPopupSet {
min-width: 1px;
}
%ifdef MOZ_SERVICES_SYNC
/* Sync notification UI */
#sync-notifications {
-moz-binding: url("chrome://browser/content/sync/notification.xml#notificationbox");
overflow-y: visible !important;
}
#sync-notifications notification {
-moz-binding: url("chrome://browser/content/sync/notification.xml#notification");
}
%endif
/* History Swipe Animation */
#historySwipeAnimationContainer {
overflow: hidden;
}
#historySwipeAnimationPreviousPage,
#historySwipeAnimationCurrentPage,
#historySwipeAnimationNextPage {
background: none top left no-repeat white;
}
#historySwipeAnimationPreviousPage {
background-image: -moz-element(#historySwipeAnimationPreviousPageSnapshot);
}
#historySwipeAnimationCurrentPage {
background-image: -moz-element(#historySwipeAnimationCurrentPageSnapshot);
}
#historySwipeAnimationNextPage {
background-image: -moz-element(#historySwipeAnimationNextPageSnapshot);
}
/* Identity UI */
#identity-popup-content-box.unknownIdentity > #identity-popup-connectedToLabel ,
#identity-popup-content-box.unknownIdentity > #identity-popup-runByLabel ,
#identity-popup-content-box.unknownIdentity > #identity-popup-content-host ,
#identity-popup-content-box.unknownIdentity > #identity-popup-content-owner ,
#identity-popup-content-box.verifiedIdentity > #identity-popup-connectedToLabel2 ,
#identity-popup-content-box.verifiedDomain > #identity-popup-connectedToLabel2 {
display: none;
}
/* Full Screen UI */
#fullscr-toggler {
height: 1px;
background: black;
}
#full-screen-warning-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 2147483647 !important;
}
#full-screen-warning-container[fade-warning-out] {
transition-property: opacity !important;
transition-duration: 500ms !important;
opacity: 0.0;
}
/* When the modal fullscreen approval UI is showing, don't allow interaction
with the page, but when we're just showing the warning upon entering
fullscreen on an already approved page, do allow interaction with the page.
*/
#full-screen-warning-container:not([obscure-browser]) {
pointer-events: none;
}
#full-screen-warning-message {
/* We must specify a max-width, otherwise word-wrap:break-word doesn't
work in descendant <description> and <label> elements. Bug 630864. */
max-width: 800px;
}
#full-screen-domain-text,
#full-screen-remember-decision > .checkbox-label-box > .checkbox-label {
word-wrap: break-word;
/* We must specify a min-width, otherwise word-wrap:break-word doesn't work. Bug 630864. */
min-width: 1px;
}
#nav-bar[mode="text"] > #window-controls > toolbarbutton > .toolbarbutton-icon {
display: -moz-box;
}
#nav-bar[mode="text"] > #window-controls > toolbarbutton > .toolbarbutton-text {
display: none;
}
/* ::::: Keyboard UI Panel ::::: */
.KUI-panel-closebutton {
-moz-binding: url("chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton-image");
}
:-moz-any(.ctrlTab-preview, .allTabs-preview) > html|img,
:-moz-any(.ctrlTab-preview, .allTabs-preview) > html|canvas {
min-width: inherit;
max-width: inherit;
min-height: inherit;
max-height: inherit;
}
.ctrlTab-favicon-container,
.allTabs-favicon-container {
-moz-box-align: start;
%ifdef XP_MACOSX
-moz-box-pack: end;
%else
-moz-box-pack: start;
%endif
}
.ctrlTab-favicon,
.allTabs-favicon {
width: 16px;
height: 16px;
}
/* ::::: Ctrl-Tab Panel ::::: */
.ctrlTab-preview {
-moz-binding: url("chrome://browser/content/browser-tabPreviews.xml#ctrlTab-preview");
}
/* ::::: All Tabs Panel ::::: */
.allTabs-preview {
-moz-binding: url("chrome://browser/content/browser-tabPreviews.xml#allTabs-preview");
}
#allTabs-tab-close-button {
-moz-binding: url("chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton-image");
margin: 0;
}
/* notification anchors should only be visible when their associated
notifications are */
.notification-anchor-icon {
-moz-user-focus: normal;
}
.notification-anchor-icon:not([showing]) {
display: none;
}
/* This was added with the identity toolkit, does it have any other purpose? */
#notification-popup .text-link.custom-link {
-moz-binding: url("chrome://global/content/bindings/text.xml#text-label");
text-decoration: none;
}
#invalid-form-popup > description {
max-width: 280px;
}
.form-validation-anchor {
/* should occupy space but not be visible */
opacity: 0;
visibility: hidden;
pointer-events: none;
}
#addon-progress-notification {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#addon-progress-notification");
}
#click-to-play-plugins-notification {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#click-to-play-plugins-notification");
}
.plugin-popupnotification-centeritem {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#plugin-popupnotification-center-item");
}
/* override hidden="true" for the status bar compatibility shim
in case it was persisted for the real status bar */
#status-bar {
display: -moz-box;
}
/* Remove the resizer from the statusbar compatibility shim */
#status-bar[hideresizer] > .statusbar-resizerpanel {
display: none;
}
browser[tabmodalPromptShowing] {
-moz-user-focus: none !important;
}
/* Status panel */
statuspanel {
-moz-binding: url("chrome://browser/content/tabbrowser.xml#statuspanel");
position: fixed;
margin-top: -3em;
left: 0;
max-width: calc(100% - 5px);
pointer-events: none;
}
statuspanel:-moz-locale-dir(ltr)[mirror],
statuspanel:-moz-locale-dir(rtl):not([mirror]) {
left: auto;
right: 0;
}
statuspanel[sizelimit] {
max-width: 50%;
}
statuspanel[type=status] {
min-width: 23em;
}
@media all and (max-width: 800px) {
statuspanel[type=status] {
min-width: 33%;
}
}
statuspanel[type=overLink] {
transition: opacity 120ms ease-out;
direction: ltr;
}
statuspanel[inactive] {
transition: none;
opacity: 0;
}
statuspanel[inactive][previoustype=overLink] {
transition: opacity 200ms ease-out;
}
.statuspanel-inner {
height: 3em;
width: 100%;
-moz-box-align: end;
}
.panel-inner-arrowcontentfooter[footertype="promobox"] {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#promobox");
}
/* highlighter */
%include highlighter.css
/* gcli */
html|*#gcli-tooltip-frame,
html|*#gcli-output-frame,
#gcli-output,
#gcli-tooltip {
overflow-x: hidden;
}
.gclitoolbar-input-node,
.gclitoolbar-complete-node {
direction: ltr;
}
#developer-toolbar-toolbox-button[error-count] > .toolbarbutton-icon {
display: none;
}
#developer-toolbar-toolbox-button[error-count]:before {
content: attr(error-count);
display: -moz-box;
-moz-box-pack: center;
}
/* Responsive Mode */
.browserContainer[responsivemode] {
overflow: auto;
}
.devtools-responsiveui-toolbar:-moz-locale-dir(rtl) {
-moz-box-pack: end;
}
.browserStack[responsivemode] {
transition-duration: 200ms;
transition-timing-function: linear;
}
.browserStack[responsivemode] {
transition-property: min-width, max-width, min-height, max-height;
}
.browserStack[responsivemode][notransition] {
transition: none;
}
.toolbarbutton-badge[badge]:not([badge=""])::after {
content: attr(badge);
}
toolbarbutton[type="badged"] {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#toolbarbutton-badged");
}
/* Strict icon size for PMkit 'ui/button' */
toolbarbutton[pmkit-button="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon {
width: 16px;
height: 16px;
}
/* Remove white bar at the bottom of the screen when watching HTML5 video in fullscreen */
#main-window[inFullscreen] #global-notificationbox,
#main-window[inFullscreen] #high-priority-global-notificationbox {
visibility: collapse;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,12 @@
<stringbundleset id="stringbundleset"/>
<commandset id="mainCommandSet"/>
<commandset id="baseMenuCommandSet"/>
<commandset id="placesCommands"/>
<broadcasterset id="mainBroadcasterSet"/>
<keyset id="mainKeyset"/>
<keyset id="baseMenuKeyset"/>
<menubar id="main-menubar"/>

View file

@ -0,0 +1,64 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 Cc = Components.classes;
let Ci = Components.interfaces;
let Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerContent",
"resource://gre/modules/LoginManagerContent.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "InsecurePasswordUtils",
"resource://gre/modules/InsecurePasswordUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FormSubmitObserver",
"resource:///modules/FormSubmitObserver.jsm");
// Bug 671101 - directly using webNavigation in this context
// causes docshells to leak
this.__defineGetter__("webNavigation", function () {
return docShell.QueryInterface(Ci.nsIWebNavigation);
});
addMessageListener("WebNavigation:LoadURI", function (message) {
let flags = message.json.flags || webNavigation.LOAD_FLAGS_NONE;
webNavigation.loadURI(message.json.uri, flags, null, null, null);
});
// TabChildGlobal
var global = this;
// Load the form validation popup handler
var formSubmitObserver = new FormSubmitObserver(content, this);
addMessageListener("Browser:HideSessionRestoreButton", function (message) {
// Hide session restore button on about:home
let doc = content.document;
let container;
if (doc.documentURI.toLowerCase() == "about:home" &&
(container = doc.getElementById("sessionRestoreContainer"))){
container.hidden = true;
}
});
addEventListener("DOMFormHasPassword", function(event) {
InsecurePasswordUtils.checkForInsecurePasswords(event.target);
LoginManagerContent.onFormPassword(event);
});
addEventListener("DOMAutoComplete", function(event) {
LoginManagerContent.onUsernameInput(event);
});
addEventListener("blur", function(event) {
LoginManagerContent.onUsernameInput(event);
});
// Lazily load the finder code
addMessageListener("Finder:Initialize", function () {
let {RemoteFinderListener} = Cu.import("resource://gre/modules/RemoteFinder.jsm", {});
new RemoteFinderListener(global);
});

View file

@ -0,0 +1,32 @@
<?xml version="1.0"?>
# 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/.
<?xul-overlay href="chrome://browser/content/macBrowserOverlay.xul"?>
<overlay id="downloadManagerOverlay"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<window id="downloadManager">
#include browserMountPoints.inc
<script type="application/javascript"><![CDATA[
window.addEventListener("load", function(event) {
// Bug 405696: Map Edit -> Find command to the download manager's command
var findMenuItem = document.getElementById("menu_find");
findMenuItem.setAttribute("command", "cmd_findDownload");
findMenuItem.setAttribute("key", "key_findDownload");
// Bug 429614: Map Edit -> Select All command to download manager's command
let selectAllMenuItem = document.getElementById("menu_selectAll");
selectAllMenuItem.setAttribute("command", "cmd_selectAllDownloads");
selectAllMenuItem.setAttribute("key", "key_selectAllDownloads");
}, false);
]]></script>
</window>
</overlay>

View file

@ -0,0 +1,13 @@
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
# 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/.
<script type="application/javascript" src="chrome://global/content/printUtils.js"/>
<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"/>

View file

@ -0,0 +1,19 @@
<?xml version="1.0"?>
# -*- Mode: HTML -*-
#
# 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/.
#ifdef XP_MACOSX
<?xul-overlay href="chrome://browser/content/macBrowserOverlay.xul"?>
<window id="main-window"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
#include browserMountPoints.inc
</window>
#endif

View file

@ -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/. */
.highlighter-container {
pointer-events: none;
}
.highlighter-controls {
position: absolute;
top: 0;
left: 0;
}
.highlighter-outline-container {
overflow: hidden;
position: relative;
}
.highlighter-outline {
position: absolute;
}
.highlighter-outline[hidden] {
opacity: 0;
pointer-events: none;
display: -moz-box;
}
.highlighter-outline:not([disable-transitions]) {
transition-property: opacity, top, left, width, height;
transition-duration: 0.1s;
transition-timing-function: linear;
}
/*
* Node Infobar
*/
.highlighter-nodeinfobar-container {
position: absolute;
max-width: 95%;
}
.highlighter-nodeinfobar-container[hidden] {
opacity: 0;
pointer-events: none;
display: -moz-box;
}
.highlighter-nodeinfobar-container:not([disable-transitions]),
.highlighter-nodeinfobar-container[disable-transitions][force-transitions] {
transition-property: transform, opacity, top, left;
transition-duration: 0.1s;
transition-timing-function: linear;
}
.highlighter-nodeinfobar-text {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
direction: ltr;
}
.highlighter-nodeinfobar-button > .toolbarbutton-text {
display: none;
}
.highlighter-nodeinfobar-container:not([locked]):not(:hover) > .highlighter-nodeinfobar > .highlighter-nodeinfobar-button {
visibility: hidden;
}
.highlighter-nodeinfobar-container[locked] > .highlighter-nodeinfobar,
.highlighter-nodeinfobar-container:not([locked]):hover > .highlighter-nodeinfobar {
pointer-events: auto;
}
html|*.highlighter-nodeinfobar-id,
html|*.highlighter-nodeinfobar-classes,
html|*.highlighter-nodeinfobar-pseudo-classes,
html|*.highlighter-nodeinfobar-tagname {
-moz-user-select: text;
-moz-user-focus: normal;
cursor: text;
}
.highlighter-nodeinfobar-arrow {
display: none;
}
.highlighter-nodeinfobar-container[position="top"]:not([hide-arrow]) > .highlighter-nodeinfobar-arrow-bottom {
display: block;
}
.highlighter-nodeinfobar-container[position="bottom"]:not([hide-arrow]) > .highlighter-nodeinfobar-arrow-top {
display: block;
}
.highlighter-nodeinfobar-container[disabled] {
visibility: hidden;
}
html|*.highlighter-nodeinfobar-tagname {
text-transform: lowercase;
}

View file

@ -0,0 +1,18 @@
<?xml version="1.0"?>
# 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/.
<?xul-overlay href="chrome://browser/content/macBrowserOverlay.xul"?>
<overlay id="jsConsoleOverlay"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<window id="JSConsoleWindow">
#include browserMountPoints.inc
</window>
</overlay>

View file

@ -0,0 +1,64 @@
<?xml version="1.0"?>
# -*- Mode: HTML -*-
#
# 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://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/places/places.css" type="text/css"?>
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
<?xul-overlay href="chrome://browser/content/baseMenuOverlay.xul"?>
<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
# All DTD information is stored in a separate file so that it can be shared by
# hiddenWindow.xul.
#include browser-doctype.inc
<overlay id="hidden-overlay"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
# All JS files which are not content (only) dependent that browser.xul
# wishes to include *must* go into the global-scripts.inc file
# so that they can be shared by this overlay.
#include global-scripts.inc
<script type="application/javascript">
function OpenBrowserWindowFromDockMenu(options) {
let win = OpenBrowserWindow(options);
win.addEventListener("load", function listener() {
win.removeEventListener("load", listener);
let dockSupport = Cc["@mozilla.org/widget/macdocksupport;1"]
.getService(Ci.nsIMacDockSupport);
dockSupport.activateApplication(true);
});
return win;
}
addEventListener("load", function() { gBrowserInit.nonBrowserWindowStartup() }, false);
addEventListener("unload", function() { gBrowserInit.nonBrowserWindowShutdown() }, false);
</script>
# All sets except for popupsets (commands, keys, stringbundles and broadcasters) *must* go into the
# browser-sets.inc file for sharing with hiddenWindow.xul.
#include browser-sets.inc
# The entire main menubar is placed into browser-menubar.inc, so that it can be shared by
# hiddenWindow.xul.
#include browser-menubar.inc
<!-- Dock menu -->
<popupset>
<menupopup id="menu_mac_dockmenu">
<!-- The command cannot be cmd_newNavigator because we need to activate
the application. -->
<menuitem label="&newNavigatorCmd.label;" oncommand="OpenBrowserWindowFromDockMenu();"
id="macDockMenuNewWindow" />
<menuitem label="&newPrivateWindow.label;" oncommand="OpenBrowserWindowFromDockMenu({private: true});" />
</menupopup>
</popupset>
</overlay>

View file

@ -0,0 +1,126 @@
#ifdef 0
/* 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/. */
#endif
/**
* This class manages a cell's DOM node (not the actually cell content, a site).
* It's mostly read-only, i.e. all manipulation of both position and content
* aren't handled here.
*/
function Cell(aGrid, aNode) {
this._grid = aGrid;
this._node = aNode;
this._node._newtabCell = this;
// Register drag-and-drop event handlers.
["dragenter", "dragover", "dragexit", "drop"].forEach(function (aType) {
this._node.addEventListener(aType, this, false);
}, this);
}
Cell.prototype = {
/**
* The grid.
*/
_grid: null,
/**
* The cell's DOM node.
*/
get node() { return this._node; },
/**
* The cell's offset in the grid.
*/
get index() {
let index = this._grid.cells.indexOf(this);
// Cache this value, overwrite the getter.
Object.defineProperty(this, "index", {value: index, enumerable: true});
return index;
},
/**
* The previous cell in the grid.
*/
get previousSibling() {
let prev = this.node.previousElementSibling;
prev = prev && prev._newtabCell;
// Cache this value, overwrite the getter.
Object.defineProperty(this, "previousSibling", {value: prev, enumerable: true});
return prev;
},
/**
* The next cell in the grid.
*/
get nextSibling() {
let next = this.node.nextElementSibling;
next = next && next._newtabCell;
// Cache this value, overwrite the getter.
Object.defineProperty(this, "nextSibling", {value: next, enumerable: true});
return next;
},
/**
* The site contained in the cell, if any.
*/
get site() {
let firstChild = this.node.firstElementChild;
return firstChild && firstChild._newtabSite;
},
/**
* Checks whether the cell contains a pinned site.
* @return Whether the cell contains a pinned site.
*/
containsPinnedSite: function Cell_containsPinnedSite() {
let site = this.site;
return site && site.isPinned();
},
/**
* Checks whether the cell contains a site (is empty).
* @return Whether the cell is empty.
*/
isEmpty: function Cell_isEmpty() {
return !this.site;
},
/**
* Handles all cell events.
*/
handleEvent: function Cell_handleEvent(aEvent) {
// We're not responding to external drag/drop events
// when our parent window is in private browsing mode.
if (inPrivateBrowsingMode() && !gDrag.draggedSite)
return;
if (aEvent.type != "dragexit" && !gDrag.isValid(aEvent))
return;
switch (aEvent.type) {
case "dragenter":
aEvent.preventDefault();
gDrop.enter(this, aEvent);
break;
case "dragover":
aEvent.preventDefault();
break;
case "dragexit":
gDrop.exit(this, aEvent);
break;
case "drop":
aEvent.preventDefault();
gDrop.drop(this, aEvent);
break;
}
}
};

View file

@ -0,0 +1,151 @@
#ifdef 0
/* 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/. */
#endif
/**
* This singleton implements site dragging functionality.
*/
let gDrag = {
/**
* The site offset to the drag start point.
*/
_offsetX: null,
_offsetY: null,
/**
* The site that is dragged.
*/
_draggedSite: null,
get draggedSite() { return this._draggedSite; },
/**
* The cell width/height at the point the drag started.
*/
_cellWidth: null,
_cellHeight: null,
get cellWidth() { return this._cellWidth; },
get cellHeight() { return this._cellHeight; },
/**
* Start a new drag operation.
* @param aSite The site that's being dragged.
* @param aEvent The 'dragstart' event.
*/
start: function Drag_start(aSite, aEvent) {
this._draggedSite = aSite;
// Mark nodes as being dragged.
let selector = ".newtab-site, .newtab-control, .newtab-thumbnail";
let parentCell = aSite.node.parentNode;
let nodes = parentCell.querySelectorAll(selector);
for (let i = 0; i < nodes.length; i++)
nodes[i].setAttribute("dragged", "true");
parentCell.setAttribute("dragged", "true");
this._setDragData(aSite, aEvent);
// Store the cursor offset.
let node = aSite.node;
let rect = node.getBoundingClientRect();
this._offsetX = aEvent.clientX - rect.left;
this._offsetY = aEvent.clientY - rect.top;
// Store the cell dimensions.
let cellNode = aSite.cell.node;
this._cellWidth = cellNode.offsetWidth;
this._cellHeight = cellNode.offsetHeight;
gTransformation.freezeSitePosition(aSite);
},
/**
* Handles the 'drag' event.
* @param aSite The site that's being dragged.
* @param aEvent The 'drag' event.
*/
drag: function Drag_drag(aSite, aEvent) {
// Get the viewport size.
let {clientWidth, clientHeight} = document.documentElement;
// We'll want a padding of 5px.
let border = 5;
// Enforce minimum constraints to keep the drag image inside the window.
let left = Math.max(scrollX + aEvent.clientX - this._offsetX, border);
let top = Math.max(scrollY + aEvent.clientY - this._offsetY, border);
// Enforce maximum constraints to keep the drag image inside the window.
left = Math.min(left, scrollX + clientWidth - this.cellWidth - border);
top = Math.min(top, scrollY + clientHeight - this.cellHeight - border);
// Update the drag image's position.
gTransformation.setSitePosition(aSite, {left: left, top: top});
},
/**
* Ends the current drag operation.
* @param aSite The site that's being dragged.
* @param aEvent The 'dragend' event.
*/
end: function Drag_end(aSite, aEvent) {
let nodes = gGrid.node.querySelectorAll("[dragged]")
for (let i = 0; i < nodes.length; i++)
nodes[i].removeAttribute("dragged");
// Slide the dragged site back into its cell (may be the old or the new cell).
gTransformation.slideSiteTo(aSite, aSite.cell, {unfreeze: true});
this._draggedSite = null;
},
/**
* Checks whether we're responsible for a given drag event.
* @param aEvent The drag event to check.
* @return Whether we should handle this drag and drop operation.
*/
isValid: function Drag_isValid(aEvent) {
let link = gDragDataHelper.getLinkFromDragEvent(aEvent);
// Check that the drag data is non-empty.
// Can happen when dragging places folders.
if (!link || !link.url) {
return false;
}
// Check that we're not accepting URLs which would inherit the caller's
// principal (such as javascript: or data:).
return gLinkChecker.checkLoadURI(link.url);
},
/**
* Initializes the drag data for the current drag operation.
* @param aSite The site that's being dragged.
* @param aEvent The 'dragstart' event.
*/
_setDragData: function Drag_setDragData(aSite, aEvent) {
let {url, title} = aSite;
let dt = aEvent.dataTransfer;
dt.mozCursor = "default";
dt.effectAllowed = "move";
dt.setData("text/plain", url);
dt.setData("text/uri-list", url);
dt.setData("text/x-moz-url", url + "\n" + title);
dt.setData("text/html", "<a href=\"" + url + "\">" + url + "</a>");
// Create and use an empty drag element. We don't want to use the default
// drag image with its default opacity.
let dragElement = document.createElementNS(HTML_NAMESPACE, "div");
dragElement.classList.add("newtab-drag");
let scrollbox = document.getElementById("newtab-scrollbox");
scrollbox.appendChild(dragElement);
dt.setDragImage(dragElement, 0, 0);
// After the 'dragstart' event has been processed we can remove the
// temporary drag element from the DOM.
setTimeout(() => scrollbox.removeChild(dragElement), 0);
}
};

View file

@ -0,0 +1,22 @@
#ifdef 0
/* 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/. */
#endif
let gDragDataHelper = {
get mimeType() {
return "text/x-moz-url";
},
getLinkFromDragEvent: function DragDataHelper_getLinkFromDragEvent(aEvent) {
let dt = aEvent.dataTransfer;
if (!dt || !dt.types.contains(this.mimeType)) {
return null;
}
let data = dt.getData(this.mimeType) || "";
let [url, title] = data.split(/[\r\n]+/);
return {url: url, title: title};
}
};

View file

@ -0,0 +1,150 @@
#ifdef 0
/* 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/. */
#endif
// A little delay that prevents the grid from being too sensitive when dragging
// sites around.
const DELAY_REARRANGE_MS = 100;
/**
* This singleton implements site dropping functionality.
*/
let gDrop = {
/**
* The last drop target.
*/
_lastDropTarget: null,
/**
* Handles the 'dragenter' event.
* @param aCell The drop target cell.
*/
enter: function Drop_enter(aCell) {
this._delayedRearrange(aCell);
},
/**
* Handles the 'dragexit' event.
* @param aCell The drop target cell.
* @param aEvent The 'dragexit' event.
*/
exit: function Drop_exit(aCell, aEvent) {
if (aEvent.dataTransfer && !aEvent.dataTransfer.mozUserCancelled) {
this._delayedRearrange();
} else {
// The drag operation has been cancelled.
this._cancelDelayedArrange();
this._rearrange();
}
},
/**
* Handles the 'drop' event.
* @param aCell The drop target cell.
* @param aEvent The 'dragexit' event.
*/
drop: function Drop_drop(aCell, aEvent) {
// The cell that is the drop target could contain a pinned site. We need
// to find out where that site has gone and re-pin it there.
if (aCell.containsPinnedSite())
this._repinSitesAfterDrop(aCell);
// Pin the dragged or insert the new site.
this._pinDraggedSite(aCell, aEvent);
this._cancelDelayedArrange();
// Update the grid and move all sites to their new places.
gUpdater.updateGrid();
},
/**
* Re-pins all pinned sites in their (new) positions.
* @param aCell The drop target cell.
*/
_repinSitesAfterDrop: function Drop_repinSitesAfterDrop(aCell) {
let sites = gDropPreview.rearrange(aCell);
// Filter out pinned sites.
let pinnedSites = sites.filter(function (aSite) {
return aSite && aSite.isPinned();
});
// Re-pin all shifted pinned cells.
pinnedSites.forEach(aSite => aSite.pin(sites.indexOf(aSite)));
},
/**
* Pins the dragged site in its new place.
* @param aCell The drop target cell.
* @param aEvent The 'dragexit' event.
*/
_pinDraggedSite: function Drop_pinDraggedSite(aCell, aEvent) {
let index = aCell.index;
let draggedSite = gDrag.draggedSite;
if (draggedSite) {
// Pin the dragged site at its new place.
if (aCell != draggedSite.cell)
draggedSite.pin(index);
} else {
let link = gDragDataHelper.getLinkFromDragEvent(aEvent);
if (link) {
// A new link was dragged onto the grid. Create it by pinning its URL.
gPinnedLinks.pin(link, index);
// Make sure the newly added link is not blocked.
gBlockedLinks.unblock(link);
}
}
},
/**
* Time a rearrange with a little delay.
* @param aCell The drop target cell.
*/
_delayedRearrange: function Drop_delayedRearrange(aCell) {
// The last drop target didn't change so there's no need to re-arrange.
if (this._lastDropTarget == aCell)
return;
let self = this;
function callback() {
self._rearrangeTimeout = null;
self._rearrange(aCell);
}
this._cancelDelayedArrange();
this._rearrangeTimeout = setTimeout(callback, DELAY_REARRANGE_MS);
// Store the last drop target.
this._lastDropTarget = aCell;
},
/**
* Cancels a timed rearrange, if any.
*/
_cancelDelayedArrange: function Drop_cancelDelayedArrange() {
if (this._rearrangeTimeout) {
clearTimeout(this._rearrangeTimeout);
this._rearrangeTimeout = null;
}
},
/**
* Rearrange all sites in the grid depending on the current drop target.
* @param aCell The drop target cell.
*/
_rearrange: function Drop_rearrange(aCell) {
let sites = gGrid.sites;
// We need to rearrange the grid only if there's a current drop target.
if (aCell)
sites = gDropPreview.rearrange(aCell);
gTransformation.rearrangeSites(sites, {unfreeze: !aCell});
}
};

View file

@ -0,0 +1,222 @@
#ifdef 0
/* 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/. */
#endif
/**
* This singleton provides the ability to re-arrange the current grid to
* indicate the transformation that results from dropping a cell at a certain
* position.
*/
let gDropPreview = {
/**
* Rearranges the sites currently contained in the grid when a site would be
* dropped onto the given cell.
* @param aCell The drop target cell.
* @return The re-arranged array of sites.
*/
rearrange: function DropPreview_rearrange(aCell) {
let sites = gGrid.sites;
// Insert the dragged site into the current grid.
this._insertDraggedSite(sites, aCell);
// After the new site has been inserted we need to correct the positions
// of all pinned tabs that have been moved around.
this._repositionPinnedSites(sites, aCell);
return sites;
},
/**
* Inserts the currently dragged site into the given array of sites.
* @param aSites The array of sites to insert into.
* @param aCell The drop target cell.
*/
_insertDraggedSite: function DropPreview_insertDraggedSite(aSites, aCell) {
let dropIndex = aCell.index;
let draggedSite = gDrag.draggedSite;
// We're currently dragging a site.
if (draggedSite) {
let dragCell = draggedSite.cell;
let dragIndex = dragCell.index;
// Move the dragged site into its new position.
if (dragIndex != dropIndex) {
aSites.splice(dragIndex, 1);
aSites.splice(dropIndex, 0, draggedSite);
}
// We're handling an external drag item.
} else {
aSites.splice(dropIndex, 0, null);
}
},
/**
* Correct the position of all pinned sites that might have been moved to
* different positions after the dragged site has been inserted.
* @param aSites The array of sites containing the dragged site.
* @param aCell The drop target cell.
*/
_repositionPinnedSites:
function DropPreview_repositionPinnedSites(aSites, aCell) {
// Collect all pinned sites.
let pinnedSites = this._filterPinnedSites(aSites, aCell);
// Correct pinned site positions.
pinnedSites.forEach(function (aSite) {
aSites[aSites.indexOf(aSite)] = aSites[aSite.cell.index];
aSites[aSite.cell.index] = aSite;
}, this);
// There might be a pinned cell that got pushed out of the grid, try to
// sneak it in by removing a lower-priority cell.
if (this._hasOverflowedPinnedSite(aSites, aCell))
this._repositionOverflowedPinnedSite(aSites, aCell);
},
/**
* Filter pinned sites out of the grid that are still on their old positions
* and have not moved.
* @param aSites The array of sites to filter.
* @param aCell The drop target cell.
* @return The filtered array of sites.
*/
_filterPinnedSites: function DropPreview_filterPinnedSites(aSites, aCell) {
let draggedSite = gDrag.draggedSite;
// When dropping on a cell that contains a pinned site make sure that all
// pinned cells surrounding the drop target are moved as well.
let range = this._getPinnedRange(aCell);
return aSites.filter(function (aSite, aIndex) {
// The site must be valid, pinned and not the dragged site.
if (!aSite || aSite == draggedSite || !aSite.isPinned())
return false;
let index = aSite.cell.index;
// If it's not in the 'pinned range' it's a valid pinned site.
return (index > range.end || index < range.start);
});
},
/**
* Determines the range of pinned sites surrounding the drop target cell.
* @param aCell The drop target cell.
* @return The range of pinned cells.
*/
_getPinnedRange: function DropPreview_getPinnedRange(aCell) {
let dropIndex = aCell.index;
let range = {start: dropIndex, end: dropIndex};
// We need a pinned range only when dropping on a pinned site.
if (aCell.containsPinnedSite()) {
let links = gPinnedLinks.links;
// Find all previous siblings of the drop target that are pinned as well.
while (range.start && links[range.start - 1])
range.start--;
let maxEnd = links.length - 1;
// Find all next siblings of the drop target that are pinned as well.
while (range.end < maxEnd && links[range.end + 1])
range.end++;
}
return range;
},
/**
* Checks if the given array of sites contains a pinned site that has
* been pushed out of the grid.
* @param aSites The array of sites to check.
* @param aCell The drop target cell.
* @return Whether there is an overflowed pinned cell.
*/
_hasOverflowedPinnedSite:
function DropPreview_hasOverflowedPinnedSite(aSites, aCell) {
// If the drop target isn't pinned there's no way a pinned site has been
// pushed out of the grid so we can just exit here.
if (!aCell.containsPinnedSite())
return false;
let cells = gGrid.cells;
// No cells have been pushed out of the grid, nothing to do here.
if (aSites.length <= cells.length)
return false;
let overflowedSite = aSites[cells.length];
// Nothing to do if the site that got pushed out of the grid is not pinned.
return (overflowedSite && overflowedSite.isPinned());
},
/**
* We have a overflowed pinned site that we need to re-position so that it's
* visible again. We try to find a lower-priority cell (empty or containing
* an unpinned site) that we can move it to.
* @param aSites The array of sites.
* @param aCell The drop target cell.
*/
_repositionOverflowedPinnedSite:
function DropPreview_repositionOverflowedPinnedSite(aSites, aCell) {
// Try to find a lower-priority cell (empty or containing an unpinned site).
let index = this._indexOfLowerPrioritySite(aSites, aCell);
if (index > -1) {
let cells = gGrid.cells;
let dropIndex = aCell.index;
// Move all pinned cells to their new positions to let the overflowed
// site fit into the grid.
for (let i = index + 1, lastPosition = index; i < aSites.length; i++) {
if (i != dropIndex) {
aSites[lastPosition] = aSites[i];
lastPosition = i;
}
}
// Finally, remove the overflowed site from its previous position.
aSites.splice(cells.length, 1);
}
},
/**
* Finds the index of the last cell that is empty or contains an unpinned
* site. These are considered to be of a lower priority.
* @param aSites The array of sites.
* @param aCell The drop target cell.
* @return The cell's index.
*/
_indexOfLowerPrioritySite:
function DropPreview_indexOfLowerPrioritySite(aSites, aCell) {
let cells = gGrid.cells;
let dropIndex = aCell.index;
// Search (beginning with the last site in the grid) for a site that is
// empty or unpinned (an thus lower-priority) and can be pushed out of the
// grid instead of the pinned site.
for (let i = cells.length - 1; i >= 0; i--) {
// The cell that is our drop target is not a good choice.
if (i == dropIndex)
continue;
let site = aSites[i];
// We can use the cell only if it's empty or the site is un-pinned.
if (!site || !site.isPinned())
return i;
}
return -1;
}
};

View file

@ -0,0 +1,188 @@
#ifdef 0
/* 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/. */
#endif
/**
* This singleton provides a custom drop target detection. We need this because
* the default DnD target detection relies on the cursor's position. We want
* to pick a drop target based on the dragged site's position.
*/
let gDropTargetShim = {
/**
* Cache for the position of all cells, cleaned after drag finished.
*/
_cellPositions: null,
/**
* The last drop target that was hovered.
*/
_lastDropTarget: null,
/**
* Initializes the drop target shim.
*/
init: function DropTargetShim_init() {
let node = gGrid.node;
// Add drag event handlers.
node.addEventListener("dragstart", this, true);
node.addEventListener("dragend", this, true);
},
/**
* Handles all shim events.
*/
handleEvent: function DropTargetShim_handleEvent(aEvent) {
switch (aEvent.type) {
case "dragstart":
this._start(aEvent);
break;
case "dragover":
this._dragover(aEvent);
break;
case "dragend":
this._end(aEvent);
break;
}
},
/**
* Handles the 'dragstart' event.
* @param aEvent The 'dragstart' event.
*/
_start: function DropTargetShim_start(aEvent) {
if (aEvent.target.classList.contains("newtab-link")) {
gGrid.lock();
// XXX bug 505521 - Listen for dragover on the document.
document.documentElement.addEventListener("dragover", this, false);
}
},
/**
* Handles the 'drag' event and determines the current drop target.
* @param aEvent The 'drag' event.
*/
_drag: function DropTargetShim_drag(aEvent) {
// Let's see if we find a drop target.
let target = this._findDropTarget(aEvent);
if (target != this._lastDropTarget) {
if (this._lastDropTarget)
// We left the last drop target.
this._dispatchEvent(aEvent, "dragexit", this._lastDropTarget);
if (target)
// We're now hovering a (new) drop target.
this._dispatchEvent(aEvent, "dragenter", target);
if (this._lastDropTarget)
// We left the last drop target.
this._dispatchEvent(aEvent, "dragleave", this._lastDropTarget);
this._lastDropTarget = target;
}
},
/**
* Handles the 'dragover' event as long as bug 505521 isn't fixed to get
* current mouse cursor coordinates while dragging.
* @param aEvent The 'dragover' event.
*/
_dragover: function DropTargetShim_dragover(aEvent) {
let sourceNode = aEvent.dataTransfer.mozSourceNode.parentNode;
gDrag.drag(sourceNode._newtabSite, aEvent);
this._drag(aEvent);
},
/**
* Handles the 'dragend' event.
* @param aEvent The 'dragend' event.
*/
_end: function DropTargetShim_end(aEvent) {
// Make sure to determine the current drop target in case the dragenter
// event hasn't been fired.
this._drag(aEvent);
if (this._lastDropTarget) {
if (aEvent.dataTransfer.mozUserCancelled) {
// The drag operation was cancelled.
this._dispatchEvent(aEvent, "dragexit", this._lastDropTarget);
this._dispatchEvent(aEvent, "dragleave", this._lastDropTarget);
} else {
// A site was successfully dropped.
this._dispatchEvent(aEvent, "drop", this._lastDropTarget);
}
// Clean up.
this._lastDropTarget = null;
this._cellPositions = null;
}
gGrid.unlock();
// XXX bug 505521 - Remove the document's dragover listener.
document.documentElement.removeEventListener("dragover", this, false);
},
/**
* Determines the current drop target by matching the dragged site's position
* against all cells in the grid.
* @return The currently hovered drop target or null.
*/
_findDropTarget: function DropTargetShim_findDropTarget() {
// These are the minimum intersection values - we want to use the cell if
// the site is >= 50% hovering its position.
let minWidth = gDrag.cellWidth / 2;
let minHeight = gDrag.cellHeight / 2;
let cellPositions = this._getCellPositions();
let rect = gTransformation.getNodePosition(gDrag.draggedSite.node);
// Compare each cell's position to the dragged site's position.
for (let i = 0; i < cellPositions.length; i++) {
let inter = rect.intersect(cellPositions[i].rect);
// If the intersection is big enough we found a drop target.
if (inter.width >= minWidth && inter.height >= minHeight)
return cellPositions[i].cell;
}
// No drop target found.
return null;
},
/**
* Gets the positions of all cell nodes.
* @return The (cached) cell positions.
*/
_getCellPositions: function DropTargetShim_getCellPositions() {
if (this._cellPositions)
return this._cellPositions;
return this._cellPositions = gGrid.cells.map(function (cell) {
return {cell: cell, rect: gTransformation.getNodePosition(cell.node)};
});
},
/**
* Dispatches a custom DragEvent on the given target node.
* @param aEvent The source event.
* @param aType The event type.
* @param aTarget The target node that receives the event.
*/
_dispatchEvent:
function DropTargetShim_dispatchEvent(aEvent, aType, aTarget) {
let node = aTarget.node;
let event = document.createEvent("DragEvents");
event.initDragEvent(aType, true, true, window, 0, 0, 0, 0, 0, false, false,
false, false, 0, node, aEvent.dataTransfer);
node.dispatchEvent(event);
}
};

View file

@ -0,0 +1,171 @@
#ifdef 0
/* 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/. */
#endif
/**
* This singleton represents the grid that contains all sites.
*/
let gGrid = {
/**
* The DOM node of the grid.
*/
_node: null,
get node() { return this._node; },
/**
* The cached DOM fragment for sites.
*/
_siteFragment: null,
/**
* All cells contained in the grid.
*/
_cells: null,
get cells() { return this._cells; },
/**
* All sites contained in the grid's cells. Sites may be empty.
*/
get sites() { return [for (cell of this.cells) cell.site]; },
// Tells whether the grid has already been initialized.
get ready() { return !!this._node; },
/**
* Initializes the grid.
* @param aSelector The query selector of the grid.
*/
init: function Grid_init() {
this._node = document.getElementById("newtab-grid");
this._createSiteFragment();
this._render();
},
/**
* Creates a new site in the grid.
* @param aLink The new site's link.
* @param aCell The cell that will contain the new site.
* @return The newly created site.
*/
createSite: function Grid_createSite(aLink, aCell) {
let node = aCell.node;
node.appendChild(this._siteFragment.cloneNode(true));
return new Site(node.firstElementChild, aLink);
},
/**
* Refreshes the grid and re-creates all sites.
*/
refresh: function Grid_refresh() {
// Remove all sites.
this.cells.forEach(function (cell) {
let node = cell.node;
let child = node.firstElementChild;
if (child)
node.removeChild(child);
}, this);
// Render the grid again.
this._render();
},
/**
* Locks the grid to block all pointer events.
*/
lock: function Grid_lock() {
this.node.setAttribute("locked", "true");
},
/**
* Unlocks the grid to allow all pointer events.
*/
unlock: function Grid_unlock() {
this.node.removeAttribute("locked");
},
/**
* Creates the newtab grid.
*/
_renderGrid: function Grid_renderGrid() {
let row = document.createElementNS(HTML_NAMESPACE, "div");
let cell = document.createElementNS(HTML_NAMESPACE, "div");
row.classList.add("newtab-row");
cell.classList.add("newtab-cell");
// Clear the grid
this._node.innerHTML = "";
// Creates the structure of one row
for (let i = 0; i < gGridPrefs.gridColumns; i++) {
row.appendChild(cell.cloneNode(true));
}
// Creates the grid
for (let j = 0; j < gGridPrefs.gridRows; j++) {
this._node.appendChild(row.cloneNode(true));
}
// (Re-)initialize all cells.
let cellElements = this.node.querySelectorAll(".newtab-cell");
this._cells = [new Cell(this, cell) for (cell of cellElements)];
},
/**
* Creates the DOM fragment that is re-used when creating sites.
*/
_createSiteFragment: function Grid_createSiteFragment() {
let site = document.createElementNS(HTML_NAMESPACE, "div");
site.classList.add("newtab-site");
site.setAttribute("draggable", "true");
// Create the site's inner HTML code.
site.innerHTML =
'<a class="newtab-link">' +
' <span class="newtab-thumbnail"/>' +
' <span class="newtab-title"/>' +
'</a>' +
'<input type="button" title="' + newTabString("pin") + '"' +
' class="newtab-control newtab-control-pin"/>' +
'<input type="button" title="' + newTabString("block") + '"' +
' class="newtab-control newtab-control-block"/>';
this._siteFragment = document.createDocumentFragment();
this._siteFragment.appendChild(site);
},
/**
* Renders the sites, creates all sites and puts them into their cells.
*/
_renderSites: function Grid_renderSites() {
let cells = this.cells;
// Put sites into the cells.
let links = gLinks.getLinks();
let length = Math.min(links.length, cells.length);
for (let i = 0; i < length; i++) {
if (links[i])
this.createSite(links[i], cells[i]);
}
},
/**
* Renders the grid.
*/
_render: function Grid_render() {
if (this._shouldRenderGrid()) {
this._renderGrid();
}
this._renderSites();
},
_shouldRenderGrid : function Grid_shouldRenderGrid() {
let rowsLength = this._node.querySelectorAll(".newtab-row").length;
let cellsLength = this._node.querySelectorAll(".newtab-cell").length;
return (rowsLength != gGridPrefs.gridRows ||
cellsLength != (gGridPrefs.gridRows * gGridPrefs.gridColumns));
}
};

View file

@ -0,0 +1,209 @@
/* 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/. */
input[type=button] {
cursor: pointer;
}
/* SCROLLBOX */
#newtab-scrollbox {
display: -moz-box;
position: relative;
-moz-box-flex: 1;
-moz-user-focus: normal;
}
#newtab-scrollbox:not([page-disabled]) {
overflow: auto;
}
/* UNDO */
#newtab-undo-container {
transition: opacity 100ms ease-out;
display: -moz-box;
-moz-box-align: center;
-moz-box-pack: center;
}
#newtab-undo-container[undo-disabled] {
opacity: 0;
pointer-events: none;
}
/* TOGGLE */
#newtab-toggle {
position: absolute;
top: 12px;
right: 12px;
}
#newtab-toggle:-moz-locale-dir(rtl) {
left: 12px;
right: auto;
}
/* MARGINS */
#newtab-vertical-margin {
display: -moz-box;
position: relative;
-moz-box-flex: 1;
-moz-box-orient: vertical;
}
#newtab-margin-top {
min-height: 50px;
max-height: 80px;
display: -moz-box;
-moz-box-flex: 1;
-moz-box-align: center;
-moz-box-pack: center;
}
#newtab-margin-bottom {
min-height: 40px;
max-height: 100px;
-moz-box-flex: 1;
}
#newtab-horizontal-margin {
display: -moz-box;
-moz-box-flex: 5;
}
.newtab-side-margin {
min-width: 40px;
max-width: 300px;
-moz-box-flex: 1;
}
/* GRID */
#newtab-grid {
display: -moz-box;
-moz-box-flex: 5;
-moz-box-orient: vertical;
min-width: 600px;
min-height: 400px;
transition: 100ms ease-out;
transition-property: opacity;
}
#newtab-grid[page-disabled] {
opacity: 0;
}
#newtab-grid[locked],
#newtab-grid[page-disabled] {
pointer-events: none;
}
/* ROWS */
.newtab-row {
display: -moz-box;
-moz-box-orient: horizontal;
-moz-box-direction: normal;
-moz-box-flex: 1;
}
/* CELLS */
.newtab-cell {
display: -moz-box;
-moz-box-flex: 1;
}
/* SITES */
.newtab-site {
position: relative;
-moz-box-flex: 1;
transition: 100ms ease-out;
transition-property: top, left, opacity;
}
.newtab-site[frozen] {
position: absolute;
pointer-events: none;
}
.newtab-site[dragged] {
transition-property: none;
z-index: 10;
}
/* LINK + THUMBNAILS */
.newtab-link,
.newtab-thumbnail {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
.newtab-thumbnail {
opacity: .8;
transition: opacity 100ms ease-out;
}
.newtab-thumbnail[dragged],
.newtab-link:-moz-focusring > .newtab-thumbnail,
.newtab-site:hover > .newtab-link > .newtab-thumbnail {
opacity: 1;
}
/* TITLES */
.newtab-title {
position: absolute;
left: 0;
right: 0;
bottom: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* CONTROLS */
.newtab-control {
position: absolute;
top: 4px;
opacity: 0;
transition: opacity 100ms ease-out;
}
.newtab-control:-moz-focusring,
.newtab-site:hover > .newtab-control {
opacity: 1;
}
.newtab-control[dragged] {
opacity: 0 !important;
}
@media (-moz-touch-enabled) {
.newtab-control {
opacity: 1;
}
}
.newtab-control-pin:-moz-locale-dir(ltr),
.newtab-control-block:-moz-locale-dir(rtl) {
left: 4px;
}
.newtab-control-block:-moz-locale-dir(ltr),
.newtab-control-pin:-moz-locale-dir(rtl) {
right: 4px;
}
/* DRAG & DROP */
/*
* This is just a temporary drag element used for dataTransfer.setDragImage()
* so that we can use custom drag images and elements. It needs an opacity of
* 0.01 so that the core code detects that it's in fact a visible element.
*/
.newtab-drag {
width: 1px;
height: 1px;
background-color: #fff;
opacity: 0.01;
}

View file

@ -0,0 +1,57 @@
/* 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";
let Cu = Components.utils;
let Ci = Components.interfaces;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PageThumbs.jsm");
Cu.import("resource://gre/modules/NewTabUtils.jsm");
Cu.import("resource:///modules/promise.js");
XPCOMUtils.defineLazyModuleGetter(this, "Rect",
"resource://gre/modules/Geometry.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
let {
links: gLinks,
allPages: gAllPages,
linkChecker: gLinkChecker,
pinnedLinks: gPinnedLinks,
blockedLinks: gBlockedLinks,
gridPrefs: gGridPrefs
} = NewTabUtils;
XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() {
return Services.strings.
createBundle("chrome://browser/locale/newTab.properties");
});
function newTabString(name) gStringBundle.GetStringFromName('newtab.' + name);
function inPrivateBrowsingMode() {
return PrivateBrowsingUtils.isWindowPrivate(window);
}
const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
#include transformations.js
#include page.js
#include grid.js
#include cells.js
#include sites.js
#include drag.js
#include dragDataHelper.js
#include drop.js
#include dropTargetShim.js
#include dropPreview.js
#include updater.js
#include undo.js
// Everything is loaded. Initialize the New Tab Page.
gPage.init();

Some files were not shown because too many files have changed in this diff Show more