Merge m-c to b2g-inbound

--HG--
rename : mobile/android/base/resources/layout/home_history_split_pane_panel.xml => mobile/android/base/resources/layout-sw600dp-land/home_history_panel.xml
extra : rebase_source : d757b3473eb5f87c9ddf60be1cb545aea556ebd0
This commit is contained in:
Carsten "Tomcat" Book 2015-10-14 12:49:49 +02:00
commit 857b10eeb2
383 changed files with 9772 additions and 2905 deletions

View File

@ -39,13 +39,11 @@ ifndef MOZ_PROFILE_USE
# otherwise the rule in rules.mk doesn't run early enough.
$(TIERS) binaries:: CLOBBER $(configure_dir)/configure config.status backend.RecursiveMakeBackend
ifndef JS_STANDALONE
ifndef LIBXUL_SDK
ifdef COMPILE_ENVIRONMENT
$(TIERS) binaries:: $(topsrcdir)/js/src/configure js/src/config.status
endif
endif
endif
endif
ifdef JS_STANDALONE
.PHONY: CLOBBER
@ -106,7 +104,6 @@ install_manifest_depends = \
$(NULL)
ifndef JS_STANDALONE
ifndef LIBXUL_SDK
ifdef COMPILE_ENVIRONMENT
install_manifest_depends += \
$(topsrcdir)/js/src/configure \
@ -114,7 +111,6 @@ install_manifest_depends += \
$(NULL)
endif
endif
endif
.PHONY: install-manifests
install-manifests: $(addprefix install-,$(install_manifests))

View File

@ -3,10 +3,8 @@
# 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')
elif CONFIG['ENABLE_TESTS']:
DIRS += ['/testing/mochitest']
include('/toolkit/toolkit.mozbuild')
if CONFIG['MOZ_EXTENSIONS']:
DIRS += ['/extensions']

View File

@ -52,24 +52,14 @@ tools repackage:: $(libs-preqs)
sed -e 's/%APP_VERSION%/$(APP_VERSION)/' -e 's/%APP_NAME%/$(APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(DIST)/$(APP_NAME).app/$(LPROJ)/InfoPlist.strings
rsync -a --exclude 'mangle' --exclude 'shlibsign' --exclude-from='$(srcdir)/macbuild/Contents/MacOS-files.in' $(DIST)/bin/ $(DIST)/$(APP_NAME).app/Contents/Resources
rsync -a --include-from='$(srcdir)/macbuild/Contents/MacOS-files.in' --exclude '*' $(DIST)/bin/ $(DIST)/$(APP_NAME).app/Contents/MacOS
ifdef LIBXUL_SDK
cp $(LIBXUL_DIST)/bin/xulrunner$(BIN_SUFFIX) $(DIST)/$(APP_NAME).app/Contents/MacOS/$(APP_BINARY)
rsync -a --exclude nsinstall --copy-unsafe-links $(LIBXUL_DIST)/XUL.framework $(DIST)/$(APP_NAME).app/Contents/Frameworks
else
$(RM) $(DIST)/$(APP_NAME).app/Contents/MacOS/$(PROGRAM)
rsync -aL $(PROGRAM) $(DIST)/$(APP_NAME).app/Contents/MacOS
endif
cp -RL $(DIST)/branding/app.icns $(DIST)/$(APP_NAME).app/Contents/Resources/$(MOZ_APP_NAME).icns
printf APPLMOZB > $(DIST)/$(APP_NAME).app/Contents/PkgInfo
else # MOZ_WIDGET_TOOLKIT != cocoa
libs::
ifdef LIBXUL_SDK
cp $(LIBXUL_DIST)/bin/xulrunner-stub$(BIN_SUFFIX) $(DIST)/bin/$(APP_BINARY)
$(NSINSTALL) -D $(DIST)/bin/xulrunner
(cd $(LIBXUL_SDK)/bin && tar $(TAR_CREATE_FLAGS) - .) | (cd $(DIST)/bin/xulrunner && tar -xf -)
endif
$(NSINSTALL) -D $(DIST)/bin/chrome/icons/default
# Copy the app icon for b2g-desktop

View File

@ -4,27 +4,26 @@
# 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']:
if CONFIG['GAIADIR']:
GeckoProgram(CONFIG['MOZ_APP_NAME'] + "-bin")
else:
GeckoProgram(CONFIG['MOZ_APP_NAME'])
if CONFIG['MOZ_B2G_LOADER']:
SOURCES += [
'B2GLoader.cpp',
]
if CONFIG['GAIADIR']:
GeckoProgram(CONFIG['MOZ_APP_NAME'] + "-bin")
else:
GeckoProgram(CONFIG['MOZ_APP_NAME'])
if CONFIG['MOZ_B2G_LOADER']:
SOURCES += [
'nsBrowserApp.cpp',
'B2GLoader.cpp',
]
if CONFIG['_MSC_VER']:
# Always enter a Windows program through wmain, whether or not we're
# a console application.
WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup']
USE_LIBS += [
'zlib',
]
SOURCES += [
'nsBrowserApp.cpp',
]
if CONFIG['_MSC_VER']:
# Always enter a Windows program through wmain, whether or not we're
# a console application.
WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup']
USE_LIBS += [
'zlib',
]
for var in ('MOZ_APP_NAME', 'MOZ_APP_VERSION', 'MOZ_UPDATER'):
DEFINES[var] = CONFIG[var]

View File

@ -44,11 +44,7 @@ fi
# use custom widget for html:select
MOZ_USE_NATIVE_POPUP_WINDOWS=1
if test "$LIBXUL_SDK"; then
MOZ_XULRUNNER=1
else
MOZ_XULRUNNER=
fi
MOZ_MEDIA_NAVIGATOR=1

View File

@ -3,8 +3,7 @@
# 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')
include('/toolkit/toolkit.mozbuild')
if CONFIG['MOZ_EXTENSIONS']:
DIRS += ['/extensions']

View File

@ -3,10 +3,7 @@
# 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')
elif CONFIG['ENABLE_TESTS']:
DIRS += ['/testing/mochitest']
include('/toolkit/toolkit.mozbuild')
if CONFIG['MOZ_EXTENSIONS']:
DIRS += ['/extensions']

View File

@ -117,18 +117,10 @@ installers-%: clobber-% langpack-% repackage-win32-installer-% repackage-zip-%
# When we unpack b2g on MacOS X the platform.ini and application.ini are in slightly
# different locations that on all other platforms
ifeq (Darwin, $(OS_ARCH))
ifdef LIBXUL_SDK
GECKO_PLATFORM_INI_PATH='$(STAGEDIST)/../Frameworks/XUL.framework/Versions/$(MOZILLA_VERSION)/platform.ini'
else
GECKO_PLATFORM_INI_PATH='$(STAGEDIST)/platform.ini'
endif
B2G_APPLICATION_INI_PATH='$(STAGEDIST)/application.ini'
else
ifdef LIBXUL_SDK
GECKO_PLATFORM_INI_PATH='$(STAGEDIST)/xulrunner/platform.ini'
else
GECKO_PLATFORM_INI_PATH='$(STAGEDIST)/platform.ini'
endif
B2G_APPLICATION_INI_PATH='$(STAGEDIST)/application.ini'
endif

View File

@ -3,8 +3,7 @@
# 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')
include('/toolkit/toolkit.mozbuild')
if CONFIG['MOZ_EXTENSIONS']:
DIRS += ['/extensions']

View File

@ -62,12 +62,10 @@ libs::
$(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))
@ -107,13 +105,3 @@ tools repackage:: $(PROGRAM)
cp -RL $(DIST)/branding/document.icns $(dist_dest)/Contents/Resources/document.icns
printf APPLMOZB > $(dist_dest)/Contents/PkgInfo
endif
ifdef LIBXUL_SDK #{
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 #} LIBXUL_SDK

View File

@ -15,11 +15,6 @@ JS_PREFERENCE_FILES += [
'profile/firefox.js',
]
if CONFIG['LIBXUL_SDK']:
PREF_JS_EXPORTS += [
'profile/channel-prefs.js',
]
SOURCES += [
'nsBrowserApp.cpp',
]
@ -29,9 +24,6 @@ FINAL_TARGET_FILES.defaults.profile += ['profile/prefs.js']
DEFINES['APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
if CONFIG['LIBXUL_SDK']:
DEFINES['LIBXUL_SDK'] = True
GENERATED_INCLUDES += [
'/build',
]

View File

@ -225,11 +225,6 @@ FileExists(const char *path)
#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)
{
@ -242,55 +237,13 @@ InitXPCOMGlue(const char *argv0, nsIFile **xreDirectory)
}
char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]);
if (!lastSlash || (size_t(lastSlash - exePath) > MAXPATHLEN - sizeof(XPCOM_PATH) - 1))
if (!lastSlash || (size_t(lastSlash - exePath) > MAXPATHLEN -
sizeof(XPCOM_DLL) - 1))
return NS_ERROR_FAILURE;
strcpy(lastSlash + 1, XPCOM_PATH);
lastSlash += sizeof(XPCOM_PATH) - sizeof(XPCOM_DLL);
strcpy(lastSlash + 1, 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;
}

View File

@ -1624,6 +1624,13 @@ pref("devtools.fontinspector.enabled", true);
// version for each user.
pref("devtools.telemetry.tools.opened.version", "{}");
// Enable the JSON View tool (an inspector for application/json documents)
#ifdef MOZ_DEV_EDITION
pref("devtools.jsonview.enabled", true);
#else
pref("devtools.jsonview.enabled", false);
#endif
// Whether the character encoding menu is under the main Firefox button. This
// preference is a string so that localizers can alter it.
pref("browser.menu.showCharacterEncoding", "chrome://browser/locale/browser.properties");
@ -1728,7 +1735,6 @@ pref("loop.support_url", "https://support.mozilla.org/kb/group-conversations-fir
pref("loop.contacts.gravatars.show", false);
pref("loop.contacts.gravatars.promo", true);
pref("loop.browserSharing.showInfoBar", true);
pref("loop.contextInConversations.enabled", true);
pref("social.sidebar.unload_timeout_ms", 10000);

View File

@ -110,7 +110,7 @@ browser.jar:
content/browser/newtab/newTab.css (content/newtab/newTab.css)
content/browser/newtab/newTab.inadjacent.json (content/newtab/newTab.inadjacent.json)
content/browser/remote-newtab/newTab.xhtml (content/remote-newtab/newTab.xhtml)
* content/browser/remote-newtab/newTab.js (content/remote-newtab/newTab.js)
content/browser/remote-newtab/newTab.js (content/remote-newtab/newTab.js)
content/browser/remote-newtab/newTab.css (content/remote-newtab/newTab.css)
* content/browser/pageinfo/pageInfo.xul (content/pageinfo/pageInfo.xul)
content/browser/pageinfo/pageInfo.js (content/pageinfo/pageInfo.js)

View File

@ -181,6 +181,12 @@ const DownloadsButton = {
}
};
Object.defineProperty(this, "DownloadsButton", {
value: DownloadsButton,
enumerable: true,
writable: false
});
////////////////////////////////////////////////////////////////////////////////
//// DownloadsIndicatorView

View File

@ -208,46 +208,6 @@ body {
border-top: 1px solid #d8d8d8;
}
.new-room-view > .context-checkbox-checked {
background-color: #dbf7ff;
}
.new-room-view > .context {
border-top: 1px solid #ebebeb;
flex: 1;
border-radius: 3px 3px 0 0;
padding: 6px 15px 8px;
}
.new-room-view > .context > .context-enabled {
margin-bottom: .5rem;
display: block;
}
.new-room-view > .context > .context-enabled > input {
-moz-margin-start: 0;
}
.new-room-view > .context > .checkbox-wrapper {
height: 2rem;
margin-bottom: .5em;
line-height: 2rem;
}
.new-room-view > .context > .checkbox-wrapper > .checkbox {
border-color: #d8d8d8;
background-color: #fff;
}
.new-room-view > .context > .checkbox-wrapper > .checkbox.checked {
background-image: url("../shared/img/check.svg#check-blue");
}
.new-room-view > .context > .checkbox-wrapper > label {
color: #333;
font-size: 1.1rem;
}
.new-room-view > .btn {
flex: 1;
height: 3rem;
@ -635,55 +595,6 @@ html[dir="rtl"] .generate-url-spinner {
text-decoration: none;
}
/* DnD menu */
.dnd-status {
border: 1px solid transparent;
padding: 2px 4px;
margin: 0;
/* Undo the start border + padding so that unhovered dnd-status is aligned
as if there was no additional spacing. */
-moz-margin-start: calc(-1px + -4px);
cursor: pointer;
border-radius: 3px;
}
.dnd-status:hover {
border-color: #ddd;
background-color: #f1f1f1;
}
.status-available:before,
.status-unavailable:before {
content: "";
display: inline-block;
width: 16px;
height: 16px;
vertical-align: bottom;
background-repeat: no-repeat;
background-size: cover;
-moz-margin-end: .2rem;
margin-bottom: -3px;
}
.dropdown-menu-item.status-available:before,
.dropdown-menu-item.status-unavailable:before {
margin-bottom: 2px;
}
html[dir="rtl"] .dropdown-menu-item.status-available:before,
html[dir="rtl"] .dropdown-menu-item.status-unavailable:before {
margin-right: -3px;
}
.status-available:before {
background-image: url("../shared/img/icons-16x16.svg#status-available");
}
.status-unavailable:before {
background-image: url("../shared/img/icons-16x16.svg#status-unavailable");
}
/* Status badges -- Available/Unavailable */
.status {
display: inline-block;
@ -743,6 +654,12 @@ html[dir="rtl"] .user-details .dropdown-menu {
right: 14px;
}
.entries-divider {
border-left: 0;
border-right: 0;
border-bottom: solid 1px #d8d8d8;
}
html[dir="rtl"] .settings-menu .dropdown-menu {
/* This is specified separately rather than using -moz-margin-start etc, as
we need to override .dropdown-menu's values which can't use the gecko

View File

@ -13,76 +13,6 @@ loop.panel = (function(_, mozL10n) {
var Button = sharedViews.Button;
var Checkbox = sharedViews.Checkbox;
/**
* Availability drop down menu subview.
*/
var AvailabilityDropdown = React.createClass({displayName: "AvailabilityDropdown",
mixins: [sharedMixins.DropdownMenuMixin()],
getInitialState: function() {
return {
doNotDisturb: navigator.mozLoop.doNotDisturb
};
},
// XXX target event can either be the li, the span or the i tag
// this makes it easier to figure out the target by making a
// closure with the desired status already passed in.
changeAvailability: function(newAvailabilty) {
return function(event) {
// Note: side effect!
switch (newAvailabilty) {
case "available":
this.setState({doNotDisturb: false});
navigator.mozLoop.doNotDisturb = false;
break;
case "do-not-disturb":
this.setState({doNotDisturb: true});
navigator.mozLoop.doNotDisturb = true;
break;
}
this.hideDropdownMenu();
}.bind(this);
},
render: function() {
var cx = React.addons.classSet;
var availabilityDropdown = cx({
"dropdown-menu": true,
"hide": !this.state.showMenu
});
var statusIcon = cx({
"status-unavailable": this.state.doNotDisturb,
"status-available": !this.state.doNotDisturb
});
var availabilityText = this.state.doNotDisturb ?
mozL10n.get("display_name_dnd_status") :
mozL10n.get("display_name_available_status");
return (
React.createElement("div", {className: "dropdown"},
React.createElement("p", {className: "dnd-status"},
React.createElement("span", {className: statusIcon,
onClick: this.toggleDropdownMenu,
ref: "menu-button"},
availabilityText
)
),
React.createElement("ul", {className: availabilityDropdown},
React.createElement("li", {className: "dropdown-menu-item status-available",
onClick: this.changeAvailability("available")},
React.createElement("span", null, mozL10n.get("display_name_available_status"))
),
React.createElement("li", {className: "dropdown-menu-item status-unavailable",
onClick: this.changeAvailability("do-not-disturb")},
React.createElement("span", null, mozL10n.get("display_name_dnd_status"))
)
)
)
);
}
});
var GettingStartedView = React.createClass({displayName: "GettingStartedView",
mixins: [sharedMixins.WindowCloseMixin],
@ -290,6 +220,11 @@ loop.panel = (function(_, mozL10n) {
this.closeWindow();
},
handleToggleNotifications: function() {
this.props.mozLoop.doNotDisturb = !this.props.mozLoop.doNotDisturb;
this.hideDropdownMenu();
},
_isSignedIn: function() {
return !!this.props.mozLoop.userProfile;
},
@ -303,6 +238,8 @@ loop.panel = (function(_, mozL10n) {
var cx = React.addons.classSet;
var accountEntryCSSClass = this._isSignedIn() ? "entry-settings-signout" :
"entry-settings-signin";
var notificationsLabel = this.props.mozLoop.doNotDisturb ? "settings_menu_item_turnnotificationson" :
"settings_menu_item_turnnotificationsoff";
return (
React.createElement("div", {className: "settings-menu dropdown"},
@ -311,6 +248,10 @@ loop.panel = (function(_, mozL10n) {
ref: "menu-button",
title: mozL10n.get("settings_menu_button_tooltip")}),
React.createElement("ul", {className: cx({"dropdown-menu": true, hide: !this.state.showMenu})},
React.createElement(SettingsDropdownEntry, {
extraCSSClass: "entry-settings-notifications entries-divider",
label: mozL10n.get(notificationsLabel),
onClick: this.handleToggleNotifications}),
React.createElement(SettingsDropdownEntry, {
displayed: this._isSignedIn() && this.props.mozLoop.fxAEnabled,
extraCSSClass: "entry-settings-account",
@ -794,7 +735,6 @@ loop.panel = (function(_, mozL10n) {
getInitialState: function() {
return {
checked: false,
previewImage: "",
description: "",
url: ""
@ -818,7 +758,6 @@ loop.panel = (function(_, mozL10n) {
var description = metadata.title || metadata.description;
var url = metadata.url;
this.setState({
checked: false,
previewImage: previewImage,
description: description,
url: url
@ -826,55 +765,22 @@ loop.panel = (function(_, mozL10n) {
}.bind(this));
},
onCheckboxChange: function(newState) {
this.setState({checked: newState.checked});
},
handleCreateButtonClick: function() {
var createRoomAction = new sharedActions.CreateRoom({
nameTemplate: mozL10n.get("rooms_default_room_name_template")
});
if (this.state.checked) {
createRoomAction.urls = [{
location: this.state.url,
description: this.state.description,
thumbnail: this.state.previewImage
}];
}
createRoomAction.urls = [{
location: this.state.url,
description: this.state.description,
thumbnail: this.state.previewImage
}];
this.props.dispatcher.dispatch(createRoomAction);
},
render: function() {
var hostname;
try {
hostname = new URL(this.state.url).hostname;
} catch (ex) {
// Empty catch - if there's an error, then we won't show the context.
}
var contextClasses = React.addons.classSet({
context: true,
"context-checkbox-checked": this.state.checked,
hide: !hostname ||
!this.props.mozLoop.getLoopPref("contextInConversations.enabled")
});
return (
React.createElement("div", {className: "new-room-view"},
React.createElement("div", {className: contextClasses},
React.createElement(Checkbox, {checked: this.state.checked,
label: mozL10n.get("context_inroom_label2"),
onChange: this.onCheckboxChange}),
React.createElement(sharedViews.ContextUrlView, {
allowClick: false,
description: this.state.description,
showContextTitle: false,
thumbnail: this.state.previewImage,
url: this.state.url,
useDesktopPaths: true})
),
React.createElement("button", {className: "btn btn-info new-room-button",
disabled: this.props.pendingOperation,
onClick: this.handleCreateButtonClick},
@ -996,11 +902,10 @@ loop.panel = (function(_, mozL10n) {
store: this.props.roomStore}),
React.createElement("div", {className: "footer"},
React.createElement("div", {className: "user-details"},
React.createElement(AvailabilityDropdown, null)
React.createElement(AccountLink, {fxAEnabled: this.props.mozLoop.fxAEnabled,
userProfile: this.state.userProfile})
),
React.createElement("div", {className: "signin-details"},
React.createElement(AccountLink, {fxAEnabled: this.props.mozLoop.fxAEnabled,
userProfile: this.state.userProfile}),
React.createElement(SettingsDropdown, {mozLoop: this.props.mozLoop})
)
)
@ -1042,7 +947,6 @@ loop.panel = (function(_, mozL10n) {
return {
AccountLink: AccountLink,
AvailabilityDropdown: AvailabilityDropdown,
ConversationDropdown: ConversationDropdown,
GettingStartedView: GettingStartedView,
init: init,

View File

@ -13,76 +13,6 @@ loop.panel = (function(_, mozL10n) {
var Button = sharedViews.Button;
var Checkbox = sharedViews.Checkbox;
/**
* Availability drop down menu subview.
*/
var AvailabilityDropdown = React.createClass({
mixins: [sharedMixins.DropdownMenuMixin()],
getInitialState: function() {
return {
doNotDisturb: navigator.mozLoop.doNotDisturb
};
},
// XXX target event can either be the li, the span or the i tag
// this makes it easier to figure out the target by making a
// closure with the desired status already passed in.
changeAvailability: function(newAvailabilty) {
return function(event) {
// Note: side effect!
switch (newAvailabilty) {
case "available":
this.setState({doNotDisturb: false});
navigator.mozLoop.doNotDisturb = false;
break;
case "do-not-disturb":
this.setState({doNotDisturb: true});
navigator.mozLoop.doNotDisturb = true;
break;
}
this.hideDropdownMenu();
}.bind(this);
},
render: function() {
var cx = React.addons.classSet;
var availabilityDropdown = cx({
"dropdown-menu": true,
"hide": !this.state.showMenu
});
var statusIcon = cx({
"status-unavailable": this.state.doNotDisturb,
"status-available": !this.state.doNotDisturb
});
var availabilityText = this.state.doNotDisturb ?
mozL10n.get("display_name_dnd_status") :
mozL10n.get("display_name_available_status");
return (
<div className="dropdown">
<p className="dnd-status">
<span className={statusIcon}
onClick={this.toggleDropdownMenu}
ref="menu-button">
{availabilityText}
</span>
</p>
<ul className={availabilityDropdown}>
<li className="dropdown-menu-item status-available"
onClick={this.changeAvailability("available")}>
<span>{mozL10n.get("display_name_available_status")}</span>
</li>
<li className="dropdown-menu-item status-unavailable"
onClick={this.changeAvailability("do-not-disturb")}>
<span>{mozL10n.get("display_name_dnd_status")}</span>
</li>
</ul>
</div>
);
}
});
var GettingStartedView = React.createClass({
mixins: [sharedMixins.WindowCloseMixin],
@ -290,6 +220,11 @@ loop.panel = (function(_, mozL10n) {
this.closeWindow();
},
handleToggleNotifications: function() {
this.props.mozLoop.doNotDisturb = !this.props.mozLoop.doNotDisturb;
this.hideDropdownMenu();
},
_isSignedIn: function() {
return !!this.props.mozLoop.userProfile;
},
@ -303,6 +238,8 @@ loop.panel = (function(_, mozL10n) {
var cx = React.addons.classSet;
var accountEntryCSSClass = this._isSignedIn() ? "entry-settings-signout" :
"entry-settings-signin";
var notificationsLabel = this.props.mozLoop.doNotDisturb ? "settings_menu_item_turnnotificationson" :
"settings_menu_item_turnnotificationsoff";
return (
<div className="settings-menu dropdown">
@ -311,6 +248,10 @@ loop.panel = (function(_, mozL10n) {
ref="menu-button"
title={mozL10n.get("settings_menu_button_tooltip")} />
<ul className={cx({"dropdown-menu": true, hide: !this.state.showMenu})}>
<SettingsDropdownEntry
extraCSSClass="entry-settings-notifications entries-divider"
label={mozL10n.get(notificationsLabel)}
onClick={this.handleToggleNotifications} />
<SettingsDropdownEntry
displayed={this._isSignedIn() && this.props.mozLoop.fxAEnabled}
extraCSSClass="entry-settings-account"
@ -794,7 +735,6 @@ loop.panel = (function(_, mozL10n) {
getInitialState: function() {
return {
checked: false,
previewImage: "",
description: "",
url: ""
@ -818,7 +758,6 @@ loop.panel = (function(_, mozL10n) {
var description = metadata.title || metadata.description;
var url = metadata.url;
this.setState({
checked: false,
previewImage: previewImage,
description: description,
url: url
@ -826,55 +765,22 @@ loop.panel = (function(_, mozL10n) {
}.bind(this));
},
onCheckboxChange: function(newState) {
this.setState({checked: newState.checked});
},
handleCreateButtonClick: function() {
var createRoomAction = new sharedActions.CreateRoom({
nameTemplate: mozL10n.get("rooms_default_room_name_template")
});
if (this.state.checked) {
createRoomAction.urls = [{
location: this.state.url,
description: this.state.description,
thumbnail: this.state.previewImage
}];
}
createRoomAction.urls = [{
location: this.state.url,
description: this.state.description,
thumbnail: this.state.previewImage
}];
this.props.dispatcher.dispatch(createRoomAction);
},
render: function() {
var hostname;
try {
hostname = new URL(this.state.url).hostname;
} catch (ex) {
// Empty catch - if there's an error, then we won't show the context.
}
var contextClasses = React.addons.classSet({
context: true,
"context-checkbox-checked": this.state.checked,
hide: !hostname ||
!this.props.mozLoop.getLoopPref("contextInConversations.enabled")
});
return (
<div className="new-room-view">
<div className={contextClasses}>
<Checkbox checked={this.state.checked}
label={mozL10n.get("context_inroom_label2")}
onChange={this.onCheckboxChange} />
<sharedViews.ContextUrlView
allowClick={false}
description={this.state.description}
showContextTitle={false}
thumbnail={this.state.previewImage}
url={this.state.url}
useDesktopPaths={true} />
</div>
<button className="btn btn-info new-room-button"
disabled={this.props.pendingOperation}
onClick={this.handleCreateButtonClick}>
@ -996,11 +902,10 @@ loop.panel = (function(_, mozL10n) {
store={this.props.roomStore} />
<div className="footer">
<div className="user-details">
<AvailabilityDropdown />
</div>
<div className="signin-details">
<AccountLink fxAEnabled={this.props.mozLoop.fxAEnabled}
userProfile={this.state.userProfile}/>
</div>
<div className="signin-details">
<SettingsDropdown mozLoop={this.props.mozLoop}/>
</div>
</div>
@ -1042,7 +947,6 @@ loop.panel = (function(_, mozL10n) {
return {
AccountLink: AccountLink,
AvailabilityDropdown: AvailabilityDropdown,
ConversationDropdown: ConversationDropdown,
GettingStartedView: GettingStartedView,
init: init,

View File

@ -606,7 +606,6 @@ loop.roomViews = (function(mozL10n) {
getInitialState: function() {
return {
contextEnabled: this.props.mozLoop.getLoopPref("contextInConversations.enabled"),
showEditContext: false
};
},
@ -767,7 +766,7 @@ loop.roomViews = (function(mozL10n) {
};
var shouldRenderInvitationOverlay = this._shouldRenderInvitationOverlay();
var shouldRenderEditContextView = this.state.contextEnabled && this.state.showEditContext;
var shouldRenderEditContextView = this.state.showEditContext;
var roomData = this.props.roomStore.getStoreState("activeRoom");
switch(this.state.roomState) {
@ -792,7 +791,7 @@ loop.roomViews = (function(mozL10n) {
{
id: "edit",
enabled: !this.state.showEditContext,
visible: this.state.contextEnabled,
visible: true,
onClick: this.handleEditContextClick
},
{ id: "feedback" },

View File

@ -606,7 +606,6 @@ loop.roomViews = (function(mozL10n) {
getInitialState: function() {
return {
contextEnabled: this.props.mozLoop.getLoopPref("contextInConversations.enabled"),
showEditContext: false
};
},
@ -767,7 +766,7 @@ loop.roomViews = (function(mozL10n) {
};
var shouldRenderInvitationOverlay = this._shouldRenderInvitationOverlay();
var shouldRenderEditContextView = this.state.contextEnabled && this.state.showEditContext;
var shouldRenderEditContextView = this.state.showEditContext;
var roomData = this.props.roomStore.getStoreState("activeRoom");
switch(this.state.roomState) {
@ -792,7 +791,7 @@ loop.roomViews = (function(mozL10n) {
{
id: "edit",
enabled: !this.state.showEditContext,
visible: this.state.contextEnabled,
visible: true,
onClick: this.handleEditContextClick
},
{ id: "feedback" },

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 71 KiB

View File

@ -28,8 +28,6 @@ describe("loop.conversation", function() {
setLoopPref: setLoopPrefStub,
getLoopPref: function(prefName) {
switch (prefName) {
case "contextInConversations.enabled":
return false;
case "debug.sdk":
return false;
default:

View File

@ -51,12 +51,7 @@ describe("loop.panel", function() {
},
setLoopPref: sandbox.stub(),
getLoopPref: function (prefName) {
switch (prefName) {
case "contextInConversations.enabled":
return true;
default:
return "unseen";
}
return "unseen";
},
getPluralForm: function() {
return "fakeText";
@ -131,39 +126,6 @@ describe("loop.panel", function() {
});
});
describe("loop.panel.AvailabilityDropdown", function() {
var view;
beforeEach(function() {
view = TestUtils.renderIntoDocument(
React.createElement(loop.panel.AvailabilityDropdown));
});
describe("doNotDisturb preference change", function() {
beforeEach(function() {
navigator.mozLoop.doNotDisturb = true;
});
it("should toggle mozLoop.doNotDisturb to false", function() {
var availableMenuOption = view.getDOMNode()
.querySelector(".status-available");
TestUtils.Simulate.click(availableMenuOption);
expect(navigator.mozLoop.doNotDisturb).eql(false);
});
it("should toggle the dropdown menu", function() {
var availableMenuOption = view.getDOMNode()
.querySelector(".dnd-status span");
TestUtils.Simulate.click(availableMenuOption);
expect(view.state.showMenu).eql(true);
});
});
});
describe("loop.panel.PanelView", function() {
var fakeClient, dispatcher, roomStore, callUrlData;
@ -389,6 +351,46 @@ describe("loop.panel", function() {
sinon.assert.calledOnce(navigator.mozLoop.logOutFromFxA);
});
describe("Toggle Notifications", function() {
var view;
beforeEach(function() {
view = mountTestComponent();
});
it("should toggle mozLoop.doNotDisturb to false", function() {
navigator.mozLoop.doNotDisturb = true;
var toggleNotificationsMenuOption = view.getDOMNode()
.querySelector(".entry-settings-notifications");
TestUtils.Simulate.click(toggleNotificationsMenuOption);
expect(navigator.mozLoop.doNotDisturb).eql(false);
});
it("should toggle mozLoop.doNotDisturb to true", function() {
navigator.mozLoop.doNotDisturb = false;
var toggleNotificationsMenuOption = view.getDOMNode()
.querySelector(".entry-settings-notifications");
TestUtils.Simulate.click(toggleNotificationsMenuOption);
expect(navigator.mozLoop.doNotDisturb).eql(true);
});
it("should close dropdown menu", function() {
navigator.mozLoop.doNotDisturb = true;
var toggleNotificationsMenuOption = view.getDOMNode()
.querySelector(".entry-settings-notifications");
view.setState({ showMenu: true });
TestUtils.Simulate.click(toggleNotificationsMenuOption);
expect(view.state.showMenu).eql(false);
});
});
});
describe("Help", function() {
@ -826,19 +828,6 @@ describe("loop.panel", function() {
}));
}
it("should dispatch a CreateRoom action when clicking on the Start a " +
"conversation button",
function() {
navigator.mozLoop.userProfile = {email: fakeEmail};
var view = createTestComponent(false);
TestUtils.Simulate.click(view.getDOMNode().querySelector(".new-room-button"));
sinon.assert.calledWith(dispatch, new sharedActions.CreateRoom({
nameTemplate: "Fake title"
}));
});
it("should dispatch a CreateRoom action with context when clicking on the " +
"Start a conversation button", function() {
fakeMozLoop.userProfile = {email: fakeEmail};
@ -859,9 +848,6 @@ describe("loop.panel", function() {
var node = view.getDOMNode();
// Select the checkbox
TestUtils.Simulate.click(node.querySelector(".checkbox-wrapper"));
TestUtils.Simulate.click(node.querySelector(".new-room-button"));
sinon.assert.calledWith(dispatch, new sharedActions.CreateRoom({
@ -881,116 +867,6 @@ describe("loop.panel", function() {
var buttonNode = view.getDOMNode().querySelector(".new-room-button[disabled]");
expect(buttonNode).to.not.equal(null);
});
it("should show context information when a URL is available", function() {
fakeMozLoop.getSelectedTabMetadata = function (callback) {
callback({
url: "https://www.example.com",
description: "fake description",
previews: [""]
});
};
var view = createTestComponent(false);
// Simulate being visible
view.onDocumentVisible();
var contextContent = view.getDOMNode().querySelector(".context-content");
expect(contextContent).to.not.equal(null);
});
it("should cancel the checkbox when a new URL is available", function() {
fakeMozLoop.getSelectedTabMetadata = function (callback) {
callback({
url: "https://www.example.com",
description: "fake description",
previews: [""]
});
};
var view = createTestComponent(false);
view.setState({ checked: true });
// Simulate being visible
view.onDocumentVisible();
expect(view.state.checked).eql(false);
});
it("should show a default favicon when none is available", function() {
fakeMozLoop.getSelectedTabMetadata = function (callback) {
callback({
url: "https://www.example.com",
description: "fake description",
previews: [""]
});
};
var view = createTestComponent(false);
// Simulate being visible
view.onDocumentVisible();
var previewImage = view.getDOMNode().querySelector(".context-preview");
expect(previewImage.src).to.match(/loop\/shared\/img\/icons-16x16.svg#globe$/);
});
it("should not show context information when a URL is unavailable", function() {
fakeMozLoop.getSelectedTabMetadata = function (callback) {
callback({
url: "",
description: "fake description",
previews: [""]
});
};
var view = createTestComponent(false);
view.onDocumentVisible();
var contextInfo = view.getDOMNode().querySelector(".context");
expect(contextInfo.classList.contains("hide")).to.equal(true);
});
it("should show only the hostname of the url", function() {
fakeMozLoop.getSelectedTabMetadata = function (callback) {
callback({
url: "https://www.example.com:1234",
description: "fake description",
previews: [""]
});
};
var view = createTestComponent(false);
// Simulate being visible
view.onDocumentVisible();
var contextHostname = view.getDOMNode().querySelector(".context-url");
expect(contextHostname.textContent).eql("www.example.com");
});
it("should show the favicon when available", function() {
var favicon = "data:image/x-icon;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
fakeMozLoop.getSelectedTabMetadata = function (callback) {
callback({
url: "https://www.example.com:1234",
description: "fake description",
favicon: favicon,
previews: ["foo.gif"]
});
};
var view = createTestComponent(false);
// Simulate being visible.
view.onDocumentVisible();
var contextPreview = view.getDOMNode().querySelector(".context-preview");
expect(contextPreview.src).eql(favicon);
});
});
describe("loop.panel.SignInRequestView", function() {

View File

@ -215,7 +215,6 @@ var fakeFewerContacts = fakeManyContacts.slice(0, 4);
// Ensure we skip FTE completely.
case "gettingStarted.seen":
case "contacts.gravatars.promo":
case "contextInConversations.enabled":
return true;
case "contacts.gravatars.show":
return false;

View File

@ -15,7 +15,6 @@
// 1. Desktop components
// 1.1 Panel
var AvailabilityDropdown = loop.panel.AvailabilityDropdown;
var PanelView = loop.panel.PanelView;
var SignInRequestView = loop.panel.SignInRequestView;
var ContactDetailsForm = loop.contacts.ContactDetailsForm;
@ -536,8 +535,7 @@
"google-active", "history", "history-hover", "history-active", "leave",
"screen-white", "screenmute-white", "settings", "settings-hover", "settings-active",
"share-darkgrey", "tag", "tag-hover", "tag-active", "trash", "unblock",
"unblock-hover", "unblock-active", "video", "video-hover", "video-active",
"status-available", "status-unavailable"
"unblock-hover", "unblock-active", "video", "video-hover", "video-active"
]
},
@ -726,20 +724,6 @@
)
),
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
dashed: true,
height: 410,
summary: "Room list (No Context)",
width: 330},
React.createElement("div", {className: "panel"},
React.createElement(PanelView, {client: mockClient,
dispatcher: dispatcher,
mozLoop: mockMozLoopLoggedInNoContext,
notifications: notifications,
roomStore: roomStore})
)
),
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
dashed: true,
height: 410,
@ -754,20 +738,6 @@
)
),
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
dashed: true,
height: 410,
summary: "Room list (no rooms and no context)",
width: 330},
React.createElement("div", {className: "panel"},
React.createElement(PanelView, {client: mockClient,
dispatcher: dispatcher,
mozLoop: mockMozLoopNoRoomsNoContext,
notifications: notifications,
roomStore: roomStoreNoRooms})
)
),
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
dashed: true,
height: 410,
@ -924,31 +894,6 @@
)
),
React.createElement(Section, {name: "Availability Dropdown"},
React.createElement("p", {className: "note"},
React.createElement("strong", null, "Note:"), " 332px wide."
),
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
dashed: true,
height: 200,
summary: "AvailabilityDropdown",
width: 332},
React.createElement("div", {className: "panel"},
React.createElement(AvailabilityDropdown, null)
)
),
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
dashed: true,
height: 200,
summary: "AvailabilityDropdown Expanded",
width: 332},
React.createElement("div", {className: "panel force-menu-show", style: {"height": "100%", "paddingTop": "50px"}},
React.createElement(AvailabilityDropdown, null)
)
)
),
React.createElement(Section, {name: "ContactDetail"},
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
dashed: true,

View File

@ -15,7 +15,6 @@
// 1. Desktop components
// 1.1 Panel
var AvailabilityDropdown = loop.panel.AvailabilityDropdown;
var PanelView = loop.panel.PanelView;
var SignInRequestView = loop.panel.SignInRequestView;
var ContactDetailsForm = loop.contacts.ContactDetailsForm;
@ -536,8 +535,7 @@
"google-active", "history", "history-hover", "history-active", "leave",
"screen-white", "screenmute-white", "settings", "settings-hover", "settings-active",
"share-darkgrey", "tag", "tag-hover", "tag-active", "trash", "unblock",
"unblock-hover", "unblock-active", "video", "video-hover", "video-active",
"status-available", "status-unavailable"
"unblock-hover", "unblock-active", "video", "video-hover", "video-active"
]
},
@ -726,20 +724,6 @@
</div>
</FramedExample>
<FramedExample cssClass="fx-embedded-panel"
dashed={true}
height={410}
summary="Room list (No Context)"
width={330}>
<div className="panel">
<PanelView client={mockClient}
dispatcher={dispatcher}
mozLoop={mockMozLoopLoggedInNoContext}
notifications={notifications}
roomStore={roomStore} />
</div>
</FramedExample>
<FramedExample cssClass="fx-embedded-panel"
dashed={true}
height={410}
@ -754,20 +738,6 @@
</div>
</FramedExample>
<FramedExample cssClass="fx-embedded-panel"
dashed={true}
height={410}
summary="Room list (no rooms and no context)"
width={330}>
<div className="panel">
<PanelView client={mockClient}
dispatcher={dispatcher}
mozLoop={mockMozLoopNoRoomsNoContext}
notifications={notifications}
roomStore={roomStoreNoRooms} />
</div>
</FramedExample>
<FramedExample cssClass="fx-embedded-panel"
dashed={true}
height={410}
@ -924,31 +894,6 @@
</FramedExample>
</Section>
<Section name="Availability Dropdown">
<p className="note">
<strong>Note:</strong> 332px wide.
</p>
<FramedExample cssClass="fx-embedded-panel"
dashed={true}
height={200}
summary="AvailabilityDropdown"
width={332}>
<div className="panel">
<AvailabilityDropdown />
</div>
</FramedExample>
<FramedExample cssClass="fx-embedded-panel"
dashed={true}
height={200}
summary="AvailabilityDropdown Expanded"
width={332}>
<div className="panel force-menu-show" style={{"height": "100%", "paddingTop": "50px"}}>
<AvailabilityDropdown />
</div>
</FramedExample>
</Section>
<Section name="ContactDetail">
<FramedExample cssClass="fx-embedded-panel"
dashed={true}

View File

@ -1,14 +1,30 @@
"use strict"
add_task(function* () {
info("Bug 475529 - Add is the default button for the new folder dialog.");
info("Bug 475529 - Add is the default button for the new folder dialog + " +
"Bug 1206376 - Changing properties of a new bookmark while adding it " +
"acts on the last bookmark in the current container");
// Add a new bookmark at index 0 in the unfiled folder.
let insertionIndex = 0;
let newBookmark = yield PlacesUtils.bookmarks.insert({
index: insertionIndex,
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
url: "http://example.com/",
});
let newBookmarkId = yield PlacesUtils.promiseItemId(newBookmark.guid);
yield withSidebarTree("bookmarks", function* (tree) {
// Select the new bookmark in the sidebar.
let itemId = PlacesUIUtils.leftPaneQueries["UnfiledBookmarks"];
tree.selectItems([itemId]);
tree.selectItems([newBookmarkId]);
ok(tree.controller.isCommandEnabled("placesCmd_new:folder"),
"'placesCmd_new:folder' on current selected node is enabled");
// Create a new folder. Since the new bookmark is selected, and new items
// are inserted at the index of the currently selected item, the new folder
// will be inserted at index 0.
yield withBookmarksDialog(
false,
function openDialog() {
@ -24,13 +40,14 @@ add_task(function* () {
EventUtils.synthesizeKey("VK_RETURN", {}, dialogWin);
yield promiseTitleChangeNotification;
let bookmark = yield PlacesUtils.bookmarks.fetch({
let newFolder = yield PlacesUtils.bookmarks.fetch({
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
index: PlacesUtils.bookmarks.DEFAULT_INDEX
index: insertionIndex,
});
is(bookmark.title, "n", "folder name has been edited");
yield PlacesUtils.bookmarks.remove(bookmark);
is(newFolder.title, "n", "folder name has been edited");
yield PlacesUtils.bookmarks.remove(newFolder);
yield PlacesUtils.bookmarks.remove(newBookmark);
}
);
});

View File

@ -1,6 +1,6 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This 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 Cc = Components.classes;
var Ci = Components.interfaces;

View File

@ -274,8 +274,13 @@ var gPrivacyPane = {
// adjust the cookie controls status
this.readAcceptCookies();
document.getElementById("keepCookiesUntil").value = disabled ? 2 :
document.getElementById("network.cookie.lifetimePolicy").value;
let lifetimePolicy = document.getElementById("network.cookie.lifetimePolicy").value;
if (lifetimePolicy != Ci.nsICookieService.ACCEPT_NORMALLY &&
lifetimePolicy != Ci.nsICookieService.ACCEPT_SESSION &&
lifetimePolicy != Ci.nsICookieService.ACCEPT_FOR_N_DAYS) {
lifetimePolicy = Ci.nsICookieService.ACCEPT_NORMALLY;
}
document.getElementById("keepCookiesUntil").value = disabled ? 2 : lifetimePolicy;
// adjust the checked state of the sanitizeOnShutdown checkbox
document.getElementById("alwaysClear").checked = disabled ? false :
@ -408,7 +413,6 @@ var gPrivacyPane = {
* network.cookie.lifetimePolicy
* - determines how long cookies are stored:
* 0 means keep cookies until they expire
* 1 means ask how long to keep each cookie
* 2 means keep cookies until the browser is closed
*/

View File

@ -226,7 +226,6 @@
<menupopup>
<menuitem label="&expire.label;" value="0"/>
<menuitem label="&close.label;" value="2"/>
<menuitem label="&askEachTime.label;" value="1"/>
</menupopup>
</menulist>
<spacer flex="1"/>

View File

@ -8,7 +8,7 @@ browser.jar:
content/browser/preferences/aboutPermissions.css
content/browser/preferences/aboutPermissions.xml
content/browser/preferences/applicationManager.xul
* content/browser/preferences/applicationManager.js
content/browser/preferences/applicationManager.js
content/browser/preferences/blocklists.xul
content/browser/preferences/blocklists.js
* content/browser/preferences/colors.xul

View File

@ -2,7 +2,6 @@
skip-if = buildapp == "mulet"
support-files =
browser_privatebrowsing_concurrent_page.html
browser_privatebrowsing_cookieacceptdialog.html
browser_privatebrowsing_geoprompt_page.html
browser_privatebrowsing_localStorage_before_after_page.html
browser_privatebrowsing_localStorage_before_after_page2.html
@ -23,7 +22,6 @@ tags = trackingprotection
[browser_privatebrowsing_cache.js]
[browser_privatebrowsing_certexceptionsui.js]
[browser_privatebrowsing_concurrent.js]
[browser_privatebrowsing_cookieacceptdialog.js]
[browser_privatebrowsing_crh.js]
[browser_privatebrowsing_downloadLastDir.js]
[browser_privatebrowsing_downloadLastDir_c.js]

View File

@ -1,11 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>browser_privatebrowsing_cookieacceptdialog.html</title>
<script type="application/javascript">
document.cookie = "foo=bar";
</script>
</head>
<body>
</body>
</html>

View File

@ -1,128 +0,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/. */
// This test makes sure that private browsing mode disables the "remember"
// option in the cookie accept dialog.
add_task(function* test() {
// initialization
const TEST_URL = "http://mochi.test:8888/browser/browser/components/" +
"privatebrowsing/test/browser/" +
"browser_privatebrowsing_cookieacceptdialog.html";
const BLANK_URL = "http://mochi.test:8888/";
let cp = Cc["@mozilla.org/embedcomp/cookieprompt-service;1"].
getService(Ci.nsICookiePromptService);
function openCookieDialog(aWindow) {
let remember = {};
const time = (new Date("Jan 1, 2030")).getTime() / 1000;
let cookie = {
name: "foo",
value: "bar",
isDomain: true,
host: "mozilla.org",
path: "/baz",
isSecure: false,
expires: time,
status: 0,
policy: 0,
isSession: false,
expiry: time,
isHttpOnly: true,
QueryInterface: function(iid) {
const validIIDs = [Ci.nsISupports, Ci.nsICookie, Ci.nsICookie2];
for (var i = 0; i < validIIDs.length; ++i)
if (iid == validIIDs[i])
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
}
};
executeSoon(function () {
cp.cookieDialog(aWindow, cookie, "mozilla.org", 10, false, remember);
});
return BrowserTestUtils.domWindowOpened();
};
function checkRememberOption(expectedDisabled, aWindow) {
return Task.spawn(function* () {
let dialogWin = yield openCookieDialog(aWindow);
yield new Promise(resolve => {
dialogWin.addEventListener("load", function onLoad(event) {
dialogWin.removeEventListener("load", onLoad, false);
resolve();
}, false);
});
let doc = dialogWin.document;
let remember = doc.getElementById("persistDomainAcceptance");
ok(remember, "The remember checkbox should exist");
if (expectedDisabled)
is(remember.getAttribute("disabled"), "true",
"The checkbox should be disabled");
else
ok(!remember.hasAttribute("disabled"),
"The checkbox should not be disabled");
yield BrowserTestUtils.closeWindow(dialogWin);
});
};
function checkSettingDialog(aIsPrivateWindow, aWindow) {
return Task.spawn(function* () {
let dialogOpened = false;
let promiseDialogClosed = null;
function observer(subject, topic, data) {
if (topic != "domwindowopened") { return; }
Services.ww.unregisterNotification(observer);
dialogOpened = true;
promiseDialogClosed = BrowserTestUtils.closeWindow(
subject.QueryInterface(Ci.nsIDOMWindow));
}
Services.ww.registerNotification(observer);
let selectedBrowser = aWindow.gBrowser.selectedBrowser;
selectedBrowser.loadURI(TEST_URL);
yield BrowserTestUtils.browserLoaded(selectedBrowser);;
if (dialogOpened) {
ok(!aIsPrivateWindow,
"Setting dialog shown, confirm normal window");
} else {
Services.ww.unregisterNotification(observer);
ok(aIsPrivateWindow,
"Confirm setting dialog is not displayed for private window");
}
yield promiseDialogClosed;
});
};
// Ask all cookies
Services.prefs.setIntPref("network.cookie.lifetimePolicy", 1);
let win = yield BrowserTestUtils.openNewBrowserWindow();
info("Test on public window");
yield checkRememberOption(false, win);
yield checkSettingDialog(false, win);
let privateWin = yield BrowserTestUtils.openNewBrowserWindow({private: true});
info("Test on private window");
yield checkRememberOption(true, privateWin);
yield checkSettingDialog(true, privateWin);
// Cleanup
Services.prefs.clearUserPref("network.cookie.lifetimePolicy");
yield BrowserTestUtils.closeWindow(win);
yield BrowserTestUtils.closeWindow(privateWin);
});

View File

@ -20,10 +20,6 @@ endif
DEFINES += -DMOZ_APP_NAME=$(MOZ_APP_NAME) -DPREF_DIR=$(PREF_DIR)
ifdef LIBXUL_SDK
DEFINES += -DLIBXUL_SDK=1
endif
ifdef MOZ_DEBUG
DEFINES += -DMOZ_DEBUG=1
endif
@ -103,9 +99,7 @@ MOZ_PKG_MAC_ICON=branding/disk.icns
MOZ_PKG_MAC_EXTRA=--symlink '/Applications:/ '
endif
ifndef LIBXUL_SDK
INSTALL_SDK = 1
endif
include $(topsrcdir)/toolkit/mozapps/installer/signing.mk
include $(topsrcdir)/toolkit/mozapps/installer/packager.mk

View File

@ -709,15 +709,10 @@
@RESPATH@/defaults/autoconfig/prefcalls.js
@RESPATH@/browser/defaults/profile/prefs.js
#ifndef LIBXUL_SDK
; Warning: changing the path to channel-prefs.js can cause bugs (Bug 756325)
; Technically this is an app pref file, but we are keeping it in the original
; gre location for now.
@RESPATH@/defaults/pref/channel-prefs.js
#else
; For Fx-on-xr, channel-prefs lives with the app preferences. (Bug 762588)
@RESPATH@/@PREF_DIR@/channel-prefs.js
#endif
; Services (gre) prefs
#ifdef MOZ_SERVICES_NOTIFICATIONS

View File

@ -38,8 +38,6 @@ invite_facebook_button2=Share on Facebook
# Status text
display_name_guest=Guest
display_name_dnd_status=Do Not Disturb
display_name_available_status=Available
# Error bars
## LOCALIZATION NOTE(session_expired_error_description,could_not_authenticate,password_changed_question,try_again_later,could_not_connect,check_internet_connection,login_expired,service_not_available,problem_accessing_account):
@ -86,6 +84,8 @@ settings_menu_item_account=Account
settings_menu_item_settings=Settings
settings_menu_item_signout=Sign Out
settings_menu_item_signin=Sign In
settings_menu_item_turnnotificationson=Turn Notifications On
settings_menu_item_turnnotificationsoff=Turn Notifications Off
settings_menu_button_tooltip=Settings
# Contact Strings (Panel)

View File

@ -47,7 +47,6 @@
<!ENTITY expire.label "they expire">
<!ENTITY close.label "I close &brandShortName;">
<!ENTITY askEachTime.label "ask me every time">
<!ENTITY cookieExceptions.label "Exceptions…">
<!ENTITY cookieExceptions.accesskey "E">

View File

@ -124,11 +124,6 @@
background-color: -moz-Dialog;
}
#urlbar:-moz-lwtheme:not([focused="true"]),
.searchbar-textbox:-moz-lwtheme:not([focused="true"]) {
opacity: .85;
}
/* Places toolbar */
toolbarbutton.bookmark-item:not(.subviewbutton),
#personal-bookmarks[cui-areatype="toolbar"]:not([overflowedItem=true]) > #bookmarks-toolbar-placeholder {
@ -577,13 +572,13 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
/* Primary toolbar buttons */
.toolbarbutton-1 > .toolbarbutton-icon,
.toolbarbutton-1 > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon {
toolbar .toolbarbutton-1 > .toolbarbutton-icon,
toolbar .toolbarbutton-1 > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon {
max-width: 16px;
}
.toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-icon,
.toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon,
toolbar .toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-icon,
toolbar .toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon,
#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
max-width: 18px;
}
@ -622,7 +617,7 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
:-moz-any(#TabsToolbar, #nav-bar) #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
/* horizontal padding + border + actual icon width */
max-width: 32px;
max-width: 32px !important /* bug 561154 */;
}
#nav-bar #PanelUI-menu-button {
@ -707,12 +702,13 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
}
:-moz-any(#back-button, #forward-button) > .toolbarbutton-icon {
border-color: ThreeDShadow !important /* bug 561154 */;
border-color: var(--urlbar-border-color) !important /* bug 561154 */;
}
:-moz-any(#back-button, #forward-button):not(:hover):not(:active):not([open=true]) > .toolbarbutton-icon,
:-moz-any(#back-button, #forward-button)[disabled=true] > .toolbarbutton-icon {
background-color: rgba(255,255,255,.15) !important /* bug 561154 */;
background-color: rgba(255,255,255,.25) !important /* bug 561154 */;
background-clip: padding-box;
}
#back-button {
@ -845,12 +841,21 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
}
/* Location bar */
#nav-bar {
--urlbar-border-color: ThreeDShadow;
}
#nav-bar:-moz-lwtheme {
--urlbar-border-color: rgba(0,0,0,.3);
}
#urlbar,
.searchbar-textbox {
-moz-appearance: none;
padding: 0;
border: 1px solid ThreeDShadow;
border: 1px solid var(--urlbar-border-color);
border-radius: 2px;
background-clip: padding-box;
margin: 0 3px;
}
@ -863,6 +868,17 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
background-color: -moz-field;
}
#urlbar:-moz-lwtheme,
.searchbar-textbox:-moz-lwtheme {
background-color: rgba(255,255,255,.8);
color: black;
}
#urlbar:-moz-lwtheme[focused=true],
.searchbar-textbox:-moz-lwtheme[focused=true] {
background-color: white;
}
.urlbar-textbox-container {
-moz-appearance: none;
-moz-box-align: stretch;

View File

@ -596,14 +596,14 @@ toolbarpaletteitem[place="palette"] > #personal-bookmarks > #bookmarks-toolbar-p
/* ----- PRIMARY TOOLBAR BUTTONS ----- */
.toolbarbutton-1 > .toolbarbutton-icon,
.toolbarbutton-1 > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon {
toolbar .toolbarbutton-1 > .toolbarbutton-icon,
toolbar .toolbarbutton-1 > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon {
max-width: 16px;
margin: 1px;
}
.toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-icon,
.toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon {
toolbar .toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-icon,
toolbar .toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon {
max-width: 18px;
margin: 0;
}
@ -1195,8 +1195,9 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button {
border-color: rgba(0,0,0,0.2);
}
#back-button:-moz-locale-dir(rtl) {
transform: scaleX(-1);
#back-button > .toolbarbutton-icon,
#forward-button > .toolbarbutton-icon {
max-width: none;
}
/* Back button styles */
@ -1209,6 +1210,10 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button {
border-radius: 10000px;
}
#back-button:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
#back-button:not(:-moz-lwtheme) {
height: 33px;
padding: 4px 5px 5px 3px;

View File

@ -685,13 +685,13 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
-moz-margin-end: 0;
}
.toolbarbutton-1 > .toolbarbutton-icon,
.toolbarbutton-1 > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon {
toolbar .toolbarbutton-1 > .toolbarbutton-icon,
toolbar .toolbarbutton-1 > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon {
max-width: 16px;
}
.toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-icon,
.toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon,
toolbar .toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-icon,
toolbar .toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon,
#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
max-width: 18px;
}

View File

@ -7,11 +7,7 @@ USE_RCS_MK := 1
include $(topsrcdir)/config/makefiles/makeutils.mk
ifdef MOZ_APP_BASENAME
ifdef LIBXUL_SDK
APP_INI_DEPS = $(LIBXUL_DIST)/bin/platform.ini
else
APP_INI_DEPS = $(topsrcdir)/config/milestone.txt
endif
MOZ_APP_BUILDID := $(shell cat $(DEPTH)/config/buildid)
APP_INI_DEPS += $(DEPTH)/config/buildid

View File

@ -157,16 +157,11 @@ if test -n "$MOZ_NATIVE_NSPR" -o -n "$NSPR_CFLAGS" -o -n "$NSPR_LIBS"; then
AC_MSG_ERROR([system NSPR does not support PR_UINT64 or including prtypes.h does not provide it]))
CFLAGS=$_SAVE_CFLAGS
elif test -z "$JS_POSIX_NSPR"; then
if test -z "$LIBXUL_SDK"; then
NSPR_CFLAGS="-I${LIBXUL_DIST}/include/nspr"
if test -n "$GNU_CC"; then
NSPR_LIBS="-L${LIBXUL_DIST}/lib -lnspr${NSPR_VERSION} -lplc${NSPR_VERSION} -lplds${NSPR_VERSION}"
else
NSPR_LIBS="${LIBXUL_DIST}/lib/nspr${NSPR_VERSION}.lib ${LIBXUL_DIST}/lib/plc${NSPR_VERSION}.lib ${LIBXUL_DIST}/lib/plds${NSPR_VERSION}.lib "
fi
NSPR_CFLAGS="-I${LIBXUL_DIST}/include/nspr"
if test -n "$GNU_CC"; then
NSPR_LIBS="-L${LIBXUL_DIST}/lib -lnspr${NSPR_VERSION} -lplc${NSPR_VERSION} -lplds${NSPR_VERSION}"
else
NSPR_CFLAGS=`"${LIBXUL_DIST}"/sdk/bin/nspr-config --prefix="${LIBXUL_DIST}" --includedir="${LIBXUL_DIST}/include/nspr" --cflags`
NSPR_LIBS=`"${LIBXUL_DIST}"/sdk/bin/nspr-config --prefix="${LIBXUL_DIST}" --libdir="${LIBXUL_DIST}"/lib --libs`
NSPR_LIBS="${LIBXUL_DIST}/lib/nspr${NSPR_VERSION}.lib ${LIBXUL_DIST}/lib/plc${NSPR_VERSION}.lib ${LIBXUL_DIST}/lib/plds${NSPR_VERSION}.lib "
fi
fi

View File

@ -101,17 +101,13 @@ automation/build: $(addprefix automation/,$(MOZ_AUTOMATION_TIERS))
AUTOMATION_EXTRA_CMDLINE-l10n-check = -j1
AUTOMATION_EXTRA_CMDLINE-pretty-l10n-check = -j1
# And force -j1 here until bug 1077670 is fixed.
AUTOMATION_EXTRA_CMDLINE-package-tests = -j1
AUTOMATION_EXTRA_CMDLINE-pretty-package-tests = -j1
# The commands only run if the corresponding MOZ_AUTOMATION_* variable is
# enabled. This means, for example, if we enable MOZ_AUTOMATION_UPLOAD, then
# 'buildsymbols' will only run if MOZ_AUTOMATION_BUILD_SYMBOLS is also set.
# However, the target automation/buildsymbols will still be executed in this
# case because it is a prerequisite of automation/upload.
define automation_commands
@$(MAKE) $1 $(AUTOMATION_EXTRA_CMDLINE-$1)
@+$(MAKE) $1 $(AUTOMATION_EXTRA_CMDLINE-$1)
$(call BUILDSTATUS,TIER_FINISH $1)
endef

View File

@ -64,7 +64,9 @@ def updated_env(env):
def build_tar_package(tar, name, base, directory):
name = os.path.realpath(name)
run_in(base, [tar,
"-c -%s -f" % ("J" if ".xz" in name else "j"),
"-c",
"-%s" % ("J" if ".xz" in name else "j"),
"-f",
name, directory])

View File

@ -301,7 +301,6 @@ ifndef IS_GYP_DIR
# NSPR_CFLAGS and NSS_CFLAGS must appear ahead of the other flags to avoid Linux
# builds wrongly picking up system NSPR/NSS header files.
OS_INCLUDES := \
$(if $(LIBXUL_SDK),-I$(LIBXUL_SDK)/include) \
$(NSPR_CFLAGS) $(NSS_CFLAGS) \
$(MOZ_JPEG_CFLAGS) \
$(MOZ_PNG_CFLAGS) \
@ -432,13 +431,8 @@ HOST_CXXFLAGS += $(HOST_DEFINES) $(MOZBUILD_HOST_CXXFLAGS)
# Override defaults
# Default location of include files
ifndef LIBXUL_SDK
IDL_PARSER_DIR = $(topsrcdir)/xpcom/idl-parser
IDL_PARSER_CACHE_DIR = $(DEPTH)/xpcom/idl-parser
else
IDL_PARSER_DIR = $(LIBXUL_SDK)/sdk/bin
IDL_PARSER_CACHE_DIR = $(LIBXUL_SDK)/sdk/bin
endif
SDK_LIB_DIR = $(DIST)/sdk/lib
SDK_BIN_DIR = $(DIST)/sdk/bin

View File

@ -5,9 +5,6 @@
include $(topsrcdir)/config/rules.mk
ifdef LIBXUL_SDK
$(error config/external/nspr/Makefile.in is not compatible with --enable-libxul-sdk=)
endif
ifdef MOZ_BUILD_NSPR
# Copy NSPR to the SDK

View File

@ -30,10 +30,6 @@ dist_idl_dir := $(DIST)/idl
dist_include_dir := $(DIST)/include
process_py := $(topsrcdir)/python/mozbuild/mozbuild/action/xpidl-process.py
ifdef LIBXUL_SDK
libxul_sdk_includes := -I$(LIBXUL_SDK)/idl
endif
# TODO we should use py_action, but that would require extra directories to be
# in the virtualenv.
%.xpt:

View File

@ -1148,7 +1148,7 @@ PREF_DIR = defaults/pref
# If DIST_SUBDIR is defined it indicates that app and gre dirs are
# different and that we are building app related resources. Hence,
# PREF_DIR should point to the app prefs location.
ifneq (,$(DIST_SUBDIR)$(XPI_NAME)$(LIBXUL_SDK))
ifneq (,$(DIST_SUBDIR)$(XPI_NAME))
PREF_DIR = defaults/preferences
endif

View File

@ -3344,11 +3344,7 @@ MOZ_CONFIG_NSPR()
dnl set GRE_MILESTONE
dnl ========================================================
if test -n "$LIBXUL_SDK"; then
GRE_MILESTONE=`$PYTHON "$_topsrcdir"/config/printconfigsetting.py "$LIBXUL_DIST"/bin/platform.ini Build Milestone`
else
GRE_MILESTONE=`tail -n 1 "$_topsrcdir"/config/milestone.txt 2>/dev/null || tail -1 "$_topsrcdir"/config/milestone.txt`
fi
GRE_MILESTONE=`tail -n 1 "$_topsrcdir"/config/milestone.txt 2>/dev/null || tail -1 "$_topsrcdir"/config/milestone.txt`
AC_SUBST(GRE_MILESTONE)
# set RELEASE_BUILD and NIGHTLY_BUILD variables depending on the cycle we're in
@ -3989,15 +3985,6 @@ if test -n "$WITH_APP_BASENAME" ; then
MOZ_APP_BASENAME="$WITH_APP_BASENAME"
fi
# Now is a good time to test for logic errors, define mismatches, etc.
case "$MOZ_BUILD_APP" in
xulrunner)
if test "$LIBXUL_SDK"; then
AC_MSG_ERROR([Building XULRunner --with-libxul-sdk doesn't make sense; XULRunner provides the libxul SDK.])
fi
;;
esac
# Special cases where we need to AC_DEFINE something. Also a holdover for apps
# that haven't made a confvars.sh yet. Don't add new stuff here, use
# MOZ_BUILD_APP.
@ -6276,11 +6263,6 @@ if test -z "$MOZ_ENABLE_GIO" -a `echo "$MOZ_EXTENSIONS" | grep -c gio` -ne 0; th
MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|gio||'`
fi
dnl Do not build gio with libxul based apps
if test -n "$LIBXUL_SDK_DIR" -a `echo "$MOZ_EXTENSIONS" | grep -c gio` -ne 0; then
MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|gio||'`
fi
if test `echo "$MOZ_EXTENSIONS" | grep -c gio` -ne 0; then
MOZ_GIO_COMPONENT=1
MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|gio||'`
@ -9139,8 +9121,7 @@ AC_SUBST(JS_SHARED_LIBRARY)
MOZ_CREATE_CONFIG_STATUS()
# No need to run subconfigures when building with LIBXUL_SDK_DIR
if test "$COMPILE_ENVIRONMENT" -a -z "$LIBXUL_SDK_DIR"; then
if test "$COMPILE_ENVIRONMENT"; then
MOZ_SUBCONFIGURE_ICU()
MOZ_SUBCONFIGURE_FFI()
MOZ_SUBCONFIGURE_JEMALLOC()
@ -9208,8 +9189,7 @@ if test -n "$_subconfigure_subdir"; then
srcdir="$_save_srcdir"
fi
# No need to run subconfigures when building with LIBXUL_SDK_DIR
if test "$COMPILE_ENVIRONMENT" -a -z "$LIBXUL_SDK_DIR"; then
if test "$COMPILE_ENVIRONMENT"; then
export WRAP_LDFLAGS
@ -9288,7 +9268,7 @@ fi
AC_OUTPUT_SUBDIRS(js/src,$cache_file)
ac_configure_args="$_SUBDIR_CONFIG_ARGS"
fi # COMPILE_ENVIRONMENT && !LIBXUL_SDK_DIR
fi # COMPILE_ENVIRONMENT
export WRITE_MOZINFO=1
dnl we need to run config.status after js/src subconfigure because we're

View File

@ -20,6 +20,7 @@
<button id="toggle-all" standalone="true" class="devtools-button pause-button"></button>
</div>
<div id="timeline-toolbar" class="theme-toolbar">
<button id="rewind-timeline" standalone="true" class="devtools-button"></button>
<button id="pause-resume-timeline" standalone="true" class="devtools-button pause-button paused"></button>
</div>
<div id="players"></div>

View File

@ -10,6 +10,8 @@
const {AnimationsTimeline} = require("devtools/client/animationinspector/components");
var $ = (selector, target = document) => target.querySelector(selector);
/**
* The main animations panel UI.
*/
@ -29,22 +31,23 @@ var AnimationsPanel = {
}
this.initialized = promise.defer();
this.playersEl = document.querySelector("#players");
this.errorMessageEl = document.querySelector("#error-message");
this.pickerButtonEl = document.querySelector("#element-picker");
this.toggleAllButtonEl = document.querySelector("#toggle-all");
this.playTimelineButtonEl = document.querySelector("#pause-resume-timeline");
this.playersEl = $("#players");
this.errorMessageEl = $("#error-message");
this.pickerButtonEl = $("#element-picker");
this.toggleAllButtonEl = $("#toggle-all");
this.playTimelineButtonEl = $("#pause-resume-timeline");
this.rewindTimelineButtonEl = $("#rewind-timeline");
// If the server doesn't support toggling all animations at once, hide the
// whole global toolbar.
if (!AnimationsController.traits.hasToggleAll) {
document.querySelector("#global-toolbar").style.display = "none";
$("#global-toolbar").style.display = "none";
}
// Binding functions that need to be called in scope.
for (let functionName of ["onPickerStarted", "onPickerStopped",
"refreshAnimations", "toggleAll", "onTabNavigated",
"onTimelineDataChanged", "playPauseTimeline"]) {
"refreshAnimationsUI", "toggleAll", "onTabNavigated",
"onTimelineDataChanged", "playPauseTimeline", "rewindTimeline"]) {
this[functionName] = this[functionName].bind(this);
}
let hUtils = gToolbox.highlighterUtils;
@ -55,7 +58,7 @@ var AnimationsPanel = {
this.startListeners();
yield this.refreshAnimations();
yield this.refreshAnimationsUI();
this.initialized.resolve();
@ -80,14 +83,14 @@ var AnimationsPanel = {
this.playersEl = this.errorMessageEl = null;
this.toggleAllButtonEl = this.pickerButtonEl = null;
this.playTimelineButtonEl = null;
this.playTimelineButtonEl = this.rewindTimelineButtonEl = null;
this.destroyed.resolve();
}),
startListeners: function() {
AnimationsController.on(AnimationsController.PLAYERS_UPDATED_EVENT,
this.refreshAnimations);
this.refreshAnimationsUI);
this.pickerButtonEl.addEventListener("click", this.togglePicker);
gToolbox.on("picker-started", this.onPickerStarted);
@ -95,6 +98,8 @@ var AnimationsPanel = {
this.toggleAllButtonEl.addEventListener("click", this.toggleAll);
this.playTimelineButtonEl.addEventListener("click", this.playPauseTimeline);
this.rewindTimelineButtonEl.addEventListener("click", this.rewindTimeline);
gToolbox.target.on("navigate", this.onTabNavigated);
this.animationsTimelineComponent.on("timeline-data-changed",
@ -103,7 +108,7 @@ var AnimationsPanel = {
stopListeners: function() {
AnimationsController.off(AnimationsController.PLAYERS_UPDATED_EVENT,
this.refreshAnimations);
this.refreshAnimationsUI);
this.pickerButtonEl.removeEventListener("click", this.togglePicker);
gToolbox.off("picker-started", this.onPickerStarted);
@ -111,6 +116,8 @@ var AnimationsPanel = {
this.toggleAllButtonEl.removeEventListener("click", this.toggleAll);
this.playTimelineButtonEl.removeEventListener("click", this.playPauseTimeline);
this.rewindTimelineButtonEl.removeEventListener("click", this.rewindTimeline);
gToolbox.target.off("navigate", this.onTabNavigated);
this.animationsTimelineComponent.off("timeline-data-changed",
@ -147,16 +154,21 @@ var AnimationsPanel = {
* If the animations are playing, this will pause them.
* If the animations are paused, this will resume them.
*/
playPauseTimeline: Task.async(function*() {
yield AnimationsController.toggleCurrentAnimations(this.timelineData.isMoving);
playPauseTimeline: function() {
AnimationsController.toggleCurrentAnimations(this.timelineData.isMoving)
.then(() => this.refreshAnimationsStateAndUI())
.catch(e => console.error(e));
},
// Now that the playState have been changed make sure the player (the
// fronts) are up to date, and then refresh the UI.
for (let player of AnimationsController.animationPlayers) {
yield player.refreshState();
}
yield this.refreshAnimations();
}),
/**
* Reset the startTime of all current animations shown in the timeline and
* pause them.
*/
rewindTimeline: function() {
AnimationsController.setCurrentTimeAll(0, true)
.then(() => this.refreshAnimationsStateAndUI())
.catch(e => console.error(e));
},
onTabNavigated: function() {
this.toggleAllButtonEl.classList.remove("paused");
@ -180,7 +192,23 @@ var AnimationsPanel = {
}
},
refreshAnimations: Task.async(function*() {
/**
* Make sure all known animations have their states up to date (which is
* useful after the playState or currentTime has been changed and in case the
* animations aren't auto-refreshing), and then refresh the UI.
*/
refreshAnimationsStateAndUI: Task.async(function*() {
for (let player of AnimationsController.animationPlayers) {
yield player.refreshState();
}
yield this.refreshAnimationsUI();
}),
/**
* Refresh the list of animations UI. This will empty the panel and re-render
* the various components again.
*/
refreshAnimationsUI: Task.async(function*() {
let done = gInspector.updating("animationspanel");
// Empty the whole panel first.

View File

@ -650,7 +650,9 @@ AnimationsTimeline.prototype = {
this.scrubberEl.style.display = "none";
} else {
this.scrubberEl.style.display = "block";
this.startAnimatingScrubber(documentCurrentTime);
this.startAnimatingScrubber(this.wasRewound()
? TimeScale.minStartTime
: documentCurrentTime);
}
},
@ -658,6 +660,11 @@ AnimationsTimeline.prototype = {
return this.animations.some(({state}) => state.playState === "running");
},
wasRewound: function() {
return !this.isAtLeastOneAnimationPlaying() &&
this.animations.every(({state}) => state.currentTime === 0);
},
startAnimatingScrubber: function(time) {
let x = TimeScale.startTimeToDistance(time, this.timeHeaderEl.offsetWidth);
this.scrubberEl.style.left = x + "px";

View File

@ -26,6 +26,7 @@ support-files =
[browser_animation_target_highlighter_lock.js]
[browser_animation_timeline_header.js]
[browser_animation_timeline_pause_button.js]
[browser_animation_timeline_rewind_button.js]
[browser_animation_timeline_scrubber_exists.js]
[browser_animation_timeline_scrubber_movable.js]
[browser_animation_timeline_scrubber_moves.js]

View File

@ -20,48 +20,16 @@ add_task(function*() {
"The play/pause button is in its playing state");
info("Click on the button to pause all timeline animations");
yield clickPlayPauseButton(panel);
yield clickTimelinePlayPauseButton(panel);
ok(btn.classList.contains("paused"),
"The play/pause button is in its paused state");
yield checkIfScrubberMoving(panel, false);
yield assertScrubberMoving(panel, false);
info("Click again on the button to play all timeline animations");
yield clickPlayPauseButton(panel);
yield clickTimelinePlayPauseButton(panel);
ok(!btn.classList.contains("paused"),
"The play/pause button is in its playing state again");
yield checkIfScrubberMoving(panel, true);
yield assertScrubberMoving(panel, true);
});
function* clickPlayPauseButton(panel) {
let onUiUpdated = panel.once(panel.UI_UPDATED_EVENT);
let btn = panel.playTimelineButtonEl;
let win = btn.ownerDocument.defaultView;
EventUtils.sendMouseEvent({type: "click"}, btn, win);
yield onUiUpdated;
yield waitForAllAnimationTargets(panel);
}
function* checkIfScrubberMoving(panel, isMoving) {
let timeline = panel.animationsTimelineComponent;
let scrubberEl = timeline.scrubberEl;
if (isMoving) {
// If we expect the scrubber to move, just wait for a couple of
// timeline-data-changed events and compare times.
let {time: time1} = yield timeline.once("timeline-data-changed");
let {time: time2} = yield timeline.once("timeline-data-changed");
ok(time2 > time1, "The scrubber is moving");
} else {
// If instead we expect the scrubber to remain at its position, just wait
// for some time. A relatively long timeout is used because the test page
// has long running animations, so the scrubber doesn't move that quickly.
let startOffset = scrubberEl.offsetLeft;
yield new Promise(r => setTimeout(r, 2000));
let endOffset = scrubberEl.offsetLeft;
is(startOffset, endOffset, "The scrubber is not moving");
}
}

View File

@ -0,0 +1,48 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Check that the timeline toolbar contains a rewind button and that it can be
// clicked. Check that when it is, the current animations displayed in the
// timeline get their playstates changed to paused, and their currentTimes
// reset to 0, and that the scrubber stops moving and is positioned to the
// start.
add_task(function*() {
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
let {panel, controller} = yield openAnimationInspector();
let btn = panel.rewindTimelineButtonEl;
ok(btn, "The rewind button exists");
info("Click on the button to rewind all timeline animations");
yield clickTimelineRewindButton(panel);
info("Check that the scrubber has stopped moving");
yield assertScrubberMoving(panel, false);
ok(controller.animationPlayers.every(({state}) => state.currentTime === 0),
"All animations' currentTimes have been set to 0");
ok(controller.animationPlayers.every(({state}) => state.playState === "paused"),
"All animations have been paused");
info("Play the animations again");
yield clickTimelinePlayPauseButton(panel);
info("And pause them after a short while");
yield new Promise(r => setTimeout(r, 200));
info("Check that rewinding when animations are paused works too");
yield clickTimelineRewindButton(panel);
info("Check that the scrubber has stopped moving");
yield assertScrubberMoving(panel, false);
ok(controller.animationPlayers.every(({state}) => state.currentTime === 0),
"All animations' currentTimes have been set to 0");
ok(controller.animationPlayers.every(({state}) => state.playState === "paused"),
"All animations have been paused");
});

View File

@ -449,3 +449,50 @@ var waitForAllAnimationTargets = Task.async(function*(panel) {
}));
return targets;
});
/**
* Check the scrubber element in the timeline is moving.
* @param {AnimationPanel} panel
* @param {Boolean} isMoving
*/
function* assertScrubberMoving(panel, isMoving) {
let timeline = panel.animationsTimelineComponent;
let scrubberEl = timeline.scrubberEl;
if (isMoving) {
// If we expect the scrubber to move, just wait for a couple of
// timeline-data-changed events and compare times.
let {time: time1} = yield timeline.once("timeline-data-changed");
let {time: time2} = yield timeline.once("timeline-data-changed");
ok(time2 > time1, "The scrubber is moving");
} else {
// If instead we expect the scrubber to remain at its position, just wait
// for some time and make sure timeline-data-changed isn't emitted.
let hasMoved = false;
timeline.once("timeline-data-changed", () => hasMoved = true);
yield new Promise(r => setTimeout(r, 500));
ok(!hasMoved, "The scrubber is not moving");
}
}
function* clickTimelinePlayPauseButton(panel) {
let onUiUpdated = panel.once(panel.UI_UPDATED_EVENT);
let btn = panel.playTimelineButtonEl;
let win = btn.ownerDocument.defaultView;
EventUtils.sendMouseEvent({type: "click"}, btn, win);
yield onUiUpdated;
yield waitForAllAnimationTargets(panel);
}
function* clickTimelineRewindButton(panel) {
let onUiUpdated = panel.once(panel.UI_UPDATED_EVENT);
let btn = panel.rewindTimelineButtonEl;
let win = btn.ownerDocument.defaultView;
EventUtils.sendMouseEvent({type: "click"}, btn, win);
yield onUiUpdated;
yield waitForAllAnimationTargets(panel);
}

View File

@ -26,6 +26,7 @@ loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main",
const DefaultTools = require("devtools/client/definitions").defaultTools;
const EventEmitter = require("devtools/shared/event-emitter");
const Telemetry = require("devtools/client/shared/telemetry");
const {JsonView} = require("devtools/client/jsonview/main");
const TABS_OPEN_PEAK_HISTOGRAM = "DEVTOOLS_TABS_OPEN_PEAK_LINEAR";
const TABS_OPEN_AVG_HISTOGRAM = "DEVTOOLS_TABS_OPEN_AVERAGE_LINEAR";
@ -51,6 +52,9 @@ this.DevTools = function DevTools() {
this.destroy = this.destroy.bind(this);
this._teardown = this._teardown.bind(this);
// JSON Viewer for 'application/json' documents.
JsonView.initialize();
EventEmitter.decorate(this);
Services.obs.addObserver(this._teardown, "devtools-unloaded", false);
@ -490,6 +494,8 @@ DevTools.prototype = {
this.unregisterTool(key, true);
}
JsonView.destroy();
this._pingTelemetry();
this._telemetry = null;

View File

@ -0,0 +1,69 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
define(function(require, exports, module) {
const React = require("react");
const { createFactories } = require("./reps/rep-utils");
const { Headers } = createFactories(require("./headers"));
const { Toolbar, ToolbarButton } = createFactories(require("./reps/toolbar"));
const DOM = React.DOM;
/**
* This template represents the 'Headers' panel
* s responsible for rendering its content.
*/
var HeadersPanel = React.createClass({
displayName: "HeadersPanel",
getInitialState: function() {
return {
data: {}
};
},
render: function() {
var data = this.props.data;
return (
DOM.div({className: "headersPanelBox"},
HeadersToolbar({actions: this.props.actions}),
DOM.div({className: "panelContent"},
Headers({data: data})
)
)
);
}
});
/**
* This template is responsible for rendering a toolbar
* within the 'Headers' panel.
*/
var HeadersToolbar = React.createFactory(React.createClass({
displayName: "HeadersToolbar",
render: function() {
return (
Toolbar({},
ToolbarButton({className: "btn copy", onClick: this.onCopy},
Locale.$STR("jsonViewer.Copy")
)
)
)
},
// Commands
onCopy: function(event) {
this.props.actions.onCopyHeaders();
},
}));
// Exports from this module
exports.HeadersPanel = HeadersPanel;
});

View File

@ -0,0 +1,100 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
define(function(require, exports, module) {
const React = require("react");
// Constants
const DOM = React.DOM;
/**
* This template is responsible for rendering basic layout
* of the 'Headers' panel. It displays HTTP headers groups such as
* received or response headers.
*/
var Headers = React.createClass({
displayName: "Headers",
getInitialState: function() {
return {};
},
render: function() {
var data = this.props.data;
return (
DOM.div({className: "netInfoHeadersTable"},
DOM.div({className: "netHeadersGroup"},
DOM.div({className: "netInfoHeadersGroup"},
DOM.span({className: "netHeader twisty"},
Locale.$STR("jsonViewer.responseHeaders")
)
),
DOM.table({cellPadding: 0, cellSpacing: 0},
HeaderList({headers: data.response})
)
),
DOM.div({className: "netHeadersGroup"},
DOM.div({className: "netInfoHeadersGroup"},
DOM.span({className: "netHeader twisty"},
Locale.$STR("jsonViewer.requestHeaders")
)
),
DOM.table({cellPadding: 0, cellSpacing: 0},
HeaderList({headers: data.request})
)
)
)
);
}
});
/**
* This template renders headers list,
* name + value pairs.
*/
var HeaderList = React.createFactory(React.createClass({
displayName: "HeaderList",
getInitialState: function() {
return {
headers: []
};
},
render: function() {
var headers = this.props.headers;
headers.sort(function(a, b) {
return a.name > b.name ? 1 : -1;
});
var rows = [];
headers.forEach(header => {
rows.push(
DOM.tr({key: header.name},
DOM.td({className: "netInfoParamName"},
DOM.span({title: header.name}, header.name)
),
DOM.td({className: "netInfoParamValue"},
DOM.code({}, header.value)
)
)
)
});
return (
DOM.tbody({},
rows
)
)
}
}));
// Exports from this module
exports.Headers = Headers;
});

View File

@ -0,0 +1,108 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
define(function(require, exports, module) {
const React = require("react");
const { createFactories } = require("./reps/rep-utils");
const { TreeView } = createFactories(require("./reps/tree-view"));
const { SearchBox } = createFactories(require("./search-box"));
const { Toolbar, ToolbarButton } = createFactories(require("./reps/toolbar"));
const DOM = React.DOM;
/**
* This template represents the 'JSON' panel. The panel is
* responsible for rendering an expandable tree that allows simple
* inspection of JSON structure.
*/
var JsonPanel = React.createClass({
displayName: "JsonPanel",
getInitialState: function() {
return {};
},
componentDidMount: function() {
document.addEventListener("keypress", this.onKeyPress, true);
},
componentWillUnmount: function() {
document.removeEventListener("keypress", this.onKeyPress, true);
},
onKeyPress: function(e) {
// XXX shortcut for focusing the Filter field (see Bug 1178771).
},
render: function() {
var content;
var data = this.props.data;
try {
if (typeof data == "object") {
content = TreeView({
data: this.props.data,
mode: "tiny",
searchFilter: this.props.searchFilter
});
} else {
content = DOM.div({className: "jsonParseError"},
data + ""
);
}
} catch (err) {
content = DOM.div({className: "jsonParseError"},
err + ""
);
}
return (
DOM.div({className: "jsonPanelBox"},
JsonToolbar({actions: this.props.actions}),
DOM.div({className: "panelContent"},
content
)
)
);
}
});
/**
* This template represents a toolbar within the 'JSON' panel.
*/
var JsonToolbar = React.createFactory(React.createClass({
displayName: "JsonToolbar",
render: function() {
return (
Toolbar({},
ToolbarButton({className: "btn save", onClick: this.onSave},
Locale.$STR("jsonViewer.Save")
),
ToolbarButton({className: "btn copy", onClick: this.onCopy},
Locale.$STR("jsonViewer.Copy")
),
SearchBox({
actions: this.props.actions
})
)
)
},
// Commands
onSave: function(event) {
this.props.actions.onSaveJson();
},
onCopy: function(event) {
this.props.actions.onCopyJson();
},
}));
// Exports from this module
exports.JsonPanel = JsonPanel;
});

View File

@ -0,0 +1,68 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
define(function(require, exports, module) {
const React = require("react");
const { createFactories } = require("./reps/rep-utils");
const { JsonPanel } = createFactories(require("./json-panel"));
const { TextPanel } = createFactories(require("./text-panel"));
const { HeadersPanel } = createFactories(require("./headers-panel"));
const { Tabs, TabPanel } = createFactories(require("./reps/tabs"));
/**
* This object represents the root application template
* responsible for rendering the basic tab layout.
*/
var MainTabbedArea = React.createClass({
displayName: "MainTabbedArea",
getInitialState: function() {
return {
json: {},
headers: {},
jsonText: this.props.jsonText,
tabActive: this.props.tabActive
};
},
onTabChanged: function(index) {
this.setState({tabActive: index});
},
render: function() {
return (
Tabs({tabActive: this.state.tabActive, onAfterChange: this.onTabChanged},
TabPanel({className: "json", title: Locale.$STR("jsonViewer.tab.JSON")},
JsonPanel({
data: this.props.json,
actions: this.props.actions,
searchFilter: this.state.searchFilter
})
),
TabPanel({className: "rawdata", title: Locale.$STR("jsonViewer.tab.RawData")},
TextPanel({
data: this.state.jsonText,
actions: this.props.actions
})
),
TabPanel({className: "headers", title: Locale.$STR("jsonViewer.tab.Headers")},
HeadersPanel({
data: this.props.headers,
actions: this.props.actions,
searchFilter: this.props.searchFilter
})
)
)
)
}
});
// Exports from this module
exports.MainTabbedArea = MainTabbedArea;
});

View File

@ -0,0 +1,18 @@
# -*- 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 += [
'reps'
]
DevToolsModules(
'headers-panel.js',
'headers.js',
'json-panel.js',
'main-tabbed-area.js',
'search-box.js',
'text-panel.js'
)

View File

@ -0,0 +1,189 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
define(function(require, exports, module) {
// Dependencies
const React = require("react");
const { createFactories } = require("./rep-utils");
const { Rep } = createFactories(require("./rep"));
const { ObjectBox } = createFactories(require("./object-box"));
const { Caption } = createFactories(require("./caption"));
// Shortcuts
const DOM = React.DOM;
/**
* Renders an array. The array is enclosed by left and right bracket
* and the max number of rendered items depends on the current mode.
*/
var ArrayRep = React.createClass({
displayName: "ArrayRep",
render: function() {
var mode = this.props.mode || "short";
var object = this.props.object;
var hasTwisty = this.hasSpecialProperties(object);
var items;
if (mode == "tiny") {
items = object.length;
} else {
var max = (mode == "short") ? 3 : 300;
items = this.arrayIterator(object, max);
}
return (
ObjectBox({className: "array", onClick: this.onToggleProperties},
DOM.a({className: "objectLink", onclick: this.onClickBracket},
DOM.span({className: "arrayLeftBracket", role: "presentation"}, "[")
),
items,
DOM.a({className: "objectLink", onclick: this.onClickBracket},
DOM.span({className: "arrayRightBracket", role: "presentation"}, "]")
),
DOM.span({className: "arrayProperties", role: "group"})
)
)
},
getTitle: function(object, context) {
return "[" + object.length + "]";
},
arrayIterator: function(array, max) {
var items = [];
for (var i=0; i<array.length && i<=max; i++) {
try {
var delim = (i == array.length-1 ? "" : ", ");
var value = array[i];
if (value === array) {
items.push(Reference({
key: i,
object: value,
delim: delim
}));
} else {
items.push(ItemRep({
key: i,
object: value,
delim: delim
}));
}
} catch (exc) {
items.push(ItemRep({object: exc, delim: delim, key: i}));
}
}
if (array.length > max + 1) {
items.pop();
items.push(Caption({
key: "more",
object: Locale.$STR("jsonViewer.reps.more"),
}));
}
return items;
},
/**
* Returns true if the passed object is an array with additional (custom)
* properties, otherwise returns false. Custom properties should be
* displayed in extra expandable section.
*
* Example array with a custom property.
* let arr = [0, 1];
* arr.myProp = "Hello";
*
* @param {Array} array The array object.
*/
hasSpecialProperties: function(array) {
function isInteger(x) {
var y = parseInt(x, 10);
if (isNaN(y)) {
return false;
}
return x === y.toString();
}
var n = 0;
var props = Object.getOwnPropertyNames(array);
for (var i=0; i<props.length; i++) {
var p = props[i];
// Valid indexes are skipped
if (isInteger(p)) {
continue;
}
// Ignore standard 'length' property, anything else is custom.
if (p != "length") {
return true;
}
}
return false;
},
// Event Handlers
onToggleProperties: function(event) {
},
onClickBracket: function(event) {
}
});
/**
* Renders array item. Individual values are separated by a comma.
*/
var ItemRep = React.createFactory(React.createClass({
displayName: "ItemRep",
render: function(){
var object = this.props.object;
var delim = this.props.delim;
return (
DOM.span({},
Rep({object: object}),
delim
)
)
}
}));
/**
* Renders cycle references in an array.
*/
var Reference = React.createFactory(React.createClass({
displayName: "Reference",
render: function(){
var tooltip = Locale.$STR("jsonView.reps.reference");
return (
span({title: tooltip},
"[...]")
)
}
}));
function supportsObject(object, type) {
return Array.isArray(object) ||
Object.prototype.toString.call(object) === "[object Arguments]";
}
// Exports from this module
exports.ArrayRep = {
rep: ArrayRep,
supportsObject: supportsObject
};
});

View File

@ -0,0 +1,31 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
define(function(require, exports, module) {
// Dependencies
const React = require("react");
const DOM = React.DOM;
/**
* Renders a caption. This template is used by other components
* that needs to distinguish between a simple text/value and a label.
*/
const Caption = React.createClass({
displayName: "Caption",
render: function() {
return (
DOM.span({"className": "caption"}, this.props.object)
);
},
});
// Exports from this module
exports.Caption = Caption;
});

View File

@ -0,0 +1,22 @@
# -*- 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/.
DevToolsModules(
'array.js',
'caption.js',
'null.js',
'number.js',
'object-box.js',
'object-link.js',
'object.js',
'rep-utils.js',
'rep.js',
'string.js',
'tabs.js',
'toolbar.js',
'tree-view.js',
'undefined.js',
)

View File

@ -0,0 +1,46 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
define(function(require, exports, module) {
// Dependencies
const React = require("react");
const { createFactories } = require("./rep-utils");
const { ObjectBox } = createFactories(require("./object-box"));
/**
* Renders null value
*/
const Null = React.createClass({
displayName: "NullRep",
render: function() {
return (
ObjectBox({className: "null"},
"null"
)
)
},
});
function supportsObject(object, type) {
if (object && object.type && object.type == "null") {
return true;
}
return (object == null);
}
// Exports from this module
exports.Null = {
rep: Null,
supportsObject: supportsObject
};
});

View File

@ -0,0 +1,47 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
define(function(require, exports, module) {
// Dependencies
const React = require("react");
const { createFactories } = require("./rep-utils");
const { ObjectBox } = createFactories(require("./object-box"));
/**
* Renders a number
*/
const Number = React.createClass({
displayName: "Number",
render: function() {
var value = this.props.object;
return (
ObjectBox({className: "number"},
this.stringify(value)
)
)
},
stringify: function(object) {
return (Object.is(object, -0) ? "-0" : String(object));
},
});
function supportsObject(object, type) {
return type == "boolean" || type == "number";
}
// Exports from this module
exports.Number = {
rep: Number,
supportsObject: supportsObject
};
});

View File

@ -0,0 +1,35 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
define(function(require, exports, module) {
// Dependencies
const React = require("react");
const DOM = React.DOM;
/**
* Renders a box for given object.
*/
const ObjectBox = React.createClass({
displayName: "ObjectBox",
render: function() {
var className = this.props.className;
var boxClassName = className ? " objectBox-" + className : "";
return (
DOM.span({className: "objectBox" + boxClassName, role: "presentation"},
this.props.children
)
)
}
});
// Exports from this module
exports.ObjectBox = ObjectBox;
});

View File

@ -0,0 +1,36 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
define(function(require, exports, module) {
// Dependencies
const React = require("react");
const DOM = React.DOM;
/**
* Renders a link for given object.
*/
const ObjectLink = React.createClass({
displayName: "ObjectLink",
render: function() {
var className = this.props.className;
var objectClassName = className ? " objectLink-" + className : "";
var linkClassName = "objectLink" + objectClassName + " a11yFocus";
return (
DOM.a({className: linkClassName, _repObject: this.props.object},
this.props.children
)
)
}
});
// Exports from this module
exports.ObjectLink = ObjectLink;
});

View File

@ -0,0 +1,178 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
define(function(require, exports, module) {
// Dependencies
const React = require("react");
const { createFactories } = require("./rep-utils");
const { ObjectBox } = createFactories(require("./object-box"));
const { Caption } = createFactories(require("./caption"));
// Shortcuts
const DOM = React.DOM;
/**
* Renders an object. An object is represented by a list of its
* properties enclosed in curly brackets.
*/
const Obj = React.createClass({
displayName: "Obj",
render: function() {
var object = this.props.object;
var props = this.shortPropIterator(object);
return (
ObjectBox({className: "object"},
DOM.span({className: "objectTitle"}, this.getTitle(object)),
DOM.span({className: "objectLeftBrace", role: "presentation"}, "{"),
props,
DOM.span({className: "objectRightBrace"}, "}")
)
)
},
getTitle: function() {
return ""; // Could also be "Object";
},
longPropIterator: function (object) {
try {
return this.propIterator(object, 100);
}
catch (err) {
console.error(err);
}
},
shortPropIterator: function (object) {
try {
return this.propIterator(object, /*could be a pref*/ 3);
}
catch (err) {
console.error(err);
}
},
propIterator: function(object, max) {
function isInterestingProp(t, value) {
return (t == "boolean" || t == "number" || (t == "string" && value) ||
(t == "object" && value && value.toString));
}
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=945377
if (Object.prototype.toString.call(object) === "[object Generator]") {
object = Object.getPrototypeOf(object);
}
// Object members with non-empty values are preferred since it gives the
// user a better overview of the object.
var props = [];
this.getProps(props, object, max, isInterestingProp);
if (props.length <= max) {
// There are not enough props yet (or at least, not enough props to
// be able to know whether we should print "more..." or not).
// Let's display also empty members and functions.
this.getProps(props, object, max, function(t, value) {
return !isInterestingProp(t, value);
});
}
if (props.length > max) {
props.pop();
props.push(Caption({
key: "more",
object: Locale.$STR("jsonViewer.reps.more"),
}));
}
else if (props.length > 0) {
// Remove the last comma.
props[props.length-1] = React.cloneElement(
props[props.length-1], { delim: "" });
}
return props;
},
getProps: function (props, object, max, filter) {
max = max || 3;
if (!object) {
return [];
}
var len = 0;
var mode = this.props.mode;
try {
for (var name in object) {
if (props.length > max) {
return;
}
var value;
try {
value = object[name];
}
catch (exc) {
continue;
}
var t = typeof(value);
if (filter(t, value)) {
props.push(PropRep({
key: name,
mode: "short",
name: name,
object: value,
equal: ": ",
delim: ", ",
mode: mode,
}));
}
}
}
catch (exc) {
}
},
});
/**
* Renders object property, name-value pair.
*/
var PropRep = React.createFactory(React.createClass({
displayName: "PropRep",
render: function(){
var { Rep } = createFactories(require("./rep"));
var object = this.props.object;
var mode = this.props.mode;
return (
DOM.span({},
DOM.span({"className": "nodeName"}, this.props.name),
DOM.span({"className": "objectEqual", role: "presentation"}, this.props.equal),
Rep({object: object, mode: mode}),
DOM.span({"className": "objectComma", role: "presentation"}, this.props.delim)
)
);
}
}));
function supportsObject(object, type) {
return true;
}
// Exports from this module
exports.Obj = {
rep: Obj,
supportsObject: supportsObject
};
});

View File

@ -0,0 +1,29 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
define(function(require, exports, module) {
// Dependencies
const React = require("react");
/**
* Create React factories for given arguments.
* Example:
* const { Rep } = createFactories(require("./rep"));
*/
function createFactories(args) {
var result = {};
for (var p in args) {
result[p] = React.createFactory(args[p]);
}
return result;
}
// Exports from this module
exports.createFactories = createFactories;
});

View File

@ -0,0 +1,87 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
define(function(require, exports, module) {
// Dependencies
const React = require("react");
// Load all existing rep templates
const { Undefined } = require("./undefined");
const { Null } = require("./null");
const { StringRep } = require("./string");
const { Number } = require("./number");
const { ArrayRep } = require("./array");
const { Obj } = require("./object");
// List of all registered template.
// XXX there should be a way for extensions to register a new
// or modify an existing rep.
var reps = [Undefined, Null, StringRep, Number, ArrayRep, Obj];
var defaultRep;
/**
* Generic rep that is using for rendering native JS types or an object.
* The right template used for rendering is picked automatically according
* to the current value type. The value must be passed is as 'object'
* property.
*/
const Rep = React.createClass({
displayName: "Rep",
render: function() {
var rep = getRep(this.props.object);
return rep(this.props);
},
});
// Helpers
/**
* Return a rep object that is responsible for rendering given
* object.
*
* @param object {Object} Object to be rendered in the UI. This
* can be generic JS object as well as a grip (handle to a remote
* debuggee object).
*/
function getRep(object) {
var type = typeof(object);
if (type == "object" && object instanceof String) {
type = "string";
}
if (isGrip(object)) {
type = object.class;
}
for (var i=0; i<reps.length; i++) {
var rep = reps[i];
try {
// supportsObject could return weight (not only true/false
// but a number), which would allow to priorities templates and
// support better extensibility.
if (rep.supportsObject(object, type)) {
return React.createFactory(rep.rep);
}
}
catch (err) {
console.error("reps.getRep; EXCEPTION ", err, err);
}
}
return React.createFactory(defaultRep.rep);
}
function isGrip(object) {
return object && object.actor;
}
// Exports from this module
exports.Rep = Rep;
});

View File

@ -0,0 +1,102 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
define(function(require, exports, module) {
// Dependencies
const React = require("react");
const { createFactories } = require("./rep-utils");
const { ObjectBox } = createFactories(require("./object-box"));
/**
* Renders a string. String value is enclosed within quotes.
*/
const StringRep = React.createClass({
displayName: "StringRep",
render: function() {
var text = this.props.object;
var member = this.props.member;
if (member && member.open) {
return (
ObjectBox({className: "string"},
"\"" + text + "\""
)
)
} else {
return (
ObjectBox({className: "string"},
"\"" + cropMultipleLines(text) + "\""
)
)
}
},
});
// Helpers
function escapeNewLines(value) {
return value.replace(/\r/gm, "\\r").replace(/\n/gm, "\\n");
};
function cropMultipleLines(text, limit) {
return escapeNewLines(cropString(text, limit));
};
function cropString(text, limit, alternativeText) {
if (!alternativeText) {
alternativeText = "...";
}
// Make sure it's a string.
text = text + "";
// Use default limit if necessary.
if (!limit) {
limit = 50;
}
// Crop the string only if a limit is actually specified.
if (limit <= 0) {
return text;
}
// Set the limit at least to the length of the alternative text
// plus one character of the original text.
if (limit <= alternativeText.length) {
limit = alternativeText.length + 1;
}
var halfLimit = (limit - alternativeText.length) / 2;
if (text.length > limit) {
return text.substr(0, Math.ceil(halfLimit)) + alternativeText +
text.substr(text.length - Math.floor(halfLimit));
}
return text;
};
function isCropped(value) {
var cropLength = 50;
return typeof(value) == "string" && value.length > cropLength;
}
function supportsObject(object, type) {
return (type == "string");
}
// Exports from this module
exports.StringRep = {
rep: StringRep,
supportsObject: supportsObject,
isCropped: isCropped
};
});

View File

@ -0,0 +1,192 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
define(function(require, exports, module) {
const React = require("react");
const DOM = React.DOM;
/**
* Renders simple 'tab' widget.
*
* Based on ReactSimpleTabs component
* https://github.com/pedronauck/react-simpletabs
*
* Component markup (+CSS) example:
*
* <div class='tabs'>
* <nav class='tabs-navigation'>
* <ul class='tabs-menu'>
* <li class='tabs-menu-item is-active'>Tab #1</li>
* <li class='tabs-menu-item'>Tab #2</li>
* </ul>
* </nav>
* <article class='tab-panel'>
* The content of active panel here
* </article>
* <div>
*/
var Tabs = React.createClass({
displayName: "Tabs",
propTypes: {
className: React.PropTypes.oneOfType([
React.PropTypes.array,
React.PropTypes.string,
React.PropTypes.object
]),
tabActive: React.PropTypes.number,
onMount: React.PropTypes.func,
onBeforeChange: React.PropTypes.func,
onAfterChange: React.PropTypes.func,
children: React.PropTypes.oneOfType([
React.PropTypes.array,
React.PropTypes.element
]).isRequired
},
getDefaultProps: function () {
return {
tabActive: 1
};
},
getInitialState: function () {
return {
tabActive: this.props.tabActive
};
},
componentDidMount: function() {
var index = this.state.tabActive;
if (this.props.onMount) {
this.props.onMount(index);
}
},
componentWillReceiveProps: function(newProps){
if (newProps.tabActive) {
this.setState({tabActive: newProps.tabActive})
}
},
render: function () {
var classNames = ["tabs", this.props.className].join(" ");
return (
DOM.div({className: classNames},
this.getMenuItems(),
this.getSelectedPanel()
)
);
},
setActive: function(index, e) {
var onAfterChange = this.props.onAfterChange;
var onBeforeChange = this.props.onBeforeChange;
if (onBeforeChange) {
var cancel = onBeforeChange(index);
if (cancel) {
return;
}
}
var newState = {
tabActive: index
};
this.setState(newState, () => {
if (onAfterChange) {
onAfterChange(index);
}
});
e.preventDefault();
},
getMenuItems: function () {
if (!this.props.children) {
throw new Error("Tabs must contain at least one Panel");
}
if (!Array.isArray(this.props.children)) {
this.props.children = [this.props.children];
}
var menuItems = this.props.children
.map(function(panel) {
return typeof panel === "function" ? panel() : panel;
}).filter(function(panel) {
return panel;
}).map(function(panel, index) {
var ref = ("tab-menu-" + (index + 1));
var title = panel.props.title;
var tabClassName = panel.props.className;
var classes = [
"tabs-menu-item",
tabClassName,
this.state.tabActive === (index + 1) && "is-active"
].join(" ");
return (
DOM.li({ref: ref, key: index, className: classes},
DOM.a({href: "#", onClick: this.setActive.bind(this, index + 1)},
title
)
)
);
}.bind(this));
return (
DOM.nav({className: "tabs-navigation"},
DOM.ul({className: "tabs-menu"},
menuItems
)
)
);
},
getSelectedPanel: function () {
var index = this.state.tabActive - 1;
var panel = this.props.children[index];
return (
DOM.article({ref: "tab-panel", className: "tab-panel"},
panel
)
);
}
});
/**
* Renders simple tab 'panel'.
*/
var Panel = React.createClass({
displayName: "Panel",
propTypes: {
title: React.PropTypes.string.isRequired,
children: React.PropTypes.oneOfType([
React.PropTypes.array,
React.PropTypes.element
]).isRequired
},
render: function () {
return DOM.div({},
this.props.children
);
}
});
// Exports from this module
exports.TabPanel = Panel;
exports.Tabs = Tabs;
});

View File

@ -0,0 +1,51 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
define(function(require, exports, module) {
const React = require("react");
const DOM = React.DOM;
/**
* Renders a simple toolbar.
*/
var Toolbar = React.createClass({
displayName: "Toolbar",
render: function() {
return (
DOM.div({className: "toolbar"},
this.props.children
)
);
}
});
/**
* Renders a simple toolbar button.
*/
var ToolbarButton = React.createClass({
displayName: "ToolbarButton",
propTypes: {
active: React.PropTypes.bool,
disabled: React.PropTypes.bool,
},
render: function() {
var props = Object.assign({className: "btn"}, this.props);
return (
DOM.button(props, this.props.children)
);
},
});
// Exports from this module
exports.Toolbar = Toolbar;
exports.ToolbarButton = ToolbarButton;
});

View File

@ -0,0 +1,261 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
define(function(require, exports, module) {
// Dependencies
const React = require("react");
const { createFactories } = require("./rep-utils");
const { Rep } = createFactories(require("./rep"));
const { StringRep } = require("./string");
const DOM = React.DOM;
var uid = 0;
/**
* Renders a tree view with expandable/collapsible items.
*/
var TreeView = React.createClass({
displayName: "TreeView",
getInitialState: function() {
return {
data: {},
searchFilter: null
};
},
// Rendering
render: function() {
var mode = this.props.mode;
var root = this.state.data;
var children = [];
if (Array.isArray(root)) {
for (var i=0; i<root.length; i++) {
var child = root[i];
children.push(TreeNode({
key: child.key,
data: child,
mode: mode,
searchFilter: this.state.searchFilter || this.props.searchFilter
}));
}
} else {
children.push(React.addons.createFragment(root));
}
return (
DOM.div({className: "domTable", cellPadding: 0, cellSpacing: 0,
onClick: this.onClick},
children
)
);
},
// Data
componentDidMount: function() {
var members = initMembers(this.props.data, 0);
this.setState({data: members, searchFilter: this.props.searchFilter});
},
componentWillReceiveProps: function(nextProps) {
var updatedState = {
searchFilter: nextProps.searchFilter
};
if (this.props.data !== nextProps.data) {
updatedState.data = initMembers(nextProps.data, 0);
}
this.setState(updatedState);
}
});
/**
* Represents a node within the tree.
*/
var TreeNode = React.createFactory(React.createClass({
displayName: "TreeNode",
getInitialState: function() {
return { data: {}, searchFilter: null };
},
componentDidMount: function() {
this.setState({data: this.props.data});
},
render: function() {
var member = this.state.data;
var mode = this.props.mode;
var classNames = ["memberRow"];
classNames.push(member.type + "Row");
if (member.hasChildren) {
classNames.push("hasChildren");
}
if (member.open) {
classNames.push("opened");
}
if (!member.children) {
// Cropped strings are expandable, but they don't have children.
var isString = typeof(member.value) == "string";
if (member.hasChildren && !isString) {
member.children = initMembers(member.value);
} else {
member.children = [];
}
}
var children = [];
if (member.open && member.children.length) {
for (var i in member.children) {
var child = member.children[i];
children.push(TreeNode({
key: child.key,
data: child,
mode: mode,
searchFilter: this.state.searchFilter || this.props.searchFilter
}));
};
}
var filter = this.props.searchFilter || "";
var name = member.name || "";
var value = member.value || "";
// Filtering is case-insensitive
filter = filter.toLowerCase();
name = name.toLowerCase();
if (filter && (name.indexOf(filter) < 0)) {
// Cache the stringify result, so the filtering is fast
// the next time.
if (!member.valueString) {
member.valueString = JSON.stringify(value).toLowerCase();
}
if (member.valueString && member.valueString.indexOf(filter) < 0) {
classNames.push("hidden");
}
}
return (
DOM.div({className: classNames.join(" "), onClick: this.onClick},
DOM.span({className: "memberLabelCell"},
DOM.span({className: "memberLabel " + member.type + "Label"},
member.name)
),
DOM.span({className: "memberValueCell"},
DOM.span({},
Rep({
object: member.value,
mode: this.props.mode,
member: member
})
)
),
DOM.div({className: "memberChildren"},
children
)
)
)
},
onClick: function(e) {
var member = this.state.data;
member.open = !member.open;
this.setState({data: member});
e.stopPropagation();
},
}));
// Helpers
function initMembers(parent) {
var members = getMembers(parent);
return members;
}
function getMembers(object) {
var members = [];
getObjectProperties(object, function(prop, value) {
var valueType = typeof(value);
var hasChildren = (valueType === "object" && hasProperties(value));
// Cropped strings are expandable, so the user can see the
// entire original value.
if (StringRep.isCropped(value)) {
hasChildren = true;
}
var type = getType(value);
var member = createMember(type, prop, value, hasChildren);
members.push(member);
});
return members;
}
function createMember(type, name, value, hasChildren) {
var member = {
name: name,
type: type,
rowClass: "memberRow-" + type,
open: "",
hasChildren: hasChildren,
value: value,
open: false,
key: uid++
};
return member;
}
function getObjectProperties(obj, callback) {
for (var p in obj) {
try {
callback.call(this, p, obj[p]);
}
catch (e) {
console.error(e)
}
}
}
function hasProperties(obj) {
if (typeof(obj) == "string") {
return false;
}
try {
for (var name in obj) {
return true;
}
}
catch (exc) {
}
return false;
}
function getType(object) {
// A type provider (or a decorator) should be used here.
return "dom";
}
// Exports from this module
exports.TreeView = TreeView;
});

View File

@ -0,0 +1,46 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
define(function(require, exports, module) {
// Dependencies
const React = require("react");
const { createFactories } = require("./rep-utils");
const { ObjectBox } = createFactories(require("./object-box"));
/**
* Renders undefined value
*/
const Undefined = React.createClass({
displayName: "UndefinedRep",
render: function() {
return (
ObjectBox({className: "undefined"},
"undefined"
)
)
},
});
function supportsObject(object, type) {
if (object && object.type && object.type == "undefined") {
return true;
}
return (type == "undefined");
}
// Exports from this module
exports.Undefined = {
rep: Undefined,
supportsObject: supportsObject
};
});

View File

@ -0,0 +1,52 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
define(function(require, exports, module) {
const React = require("react");
const DOM = React.DOM;
// For smooth incremental searching (in case the user is typing quickly).
const searchDelay = 250;
/**
* This object represents a search box located at the
* top right corner of the application.
*/
var SearchBox = React.createClass({
displayName: "SearchBox",
render: function() {
return (
DOM.input({className: "searchBox",
placeholder: Locale.$STR("jsonViewer.filterJSON"),
onChange: this.onSearch})
)
},
onSearch: function(event) {
var searchBox = event.target;
var win = searchBox.ownerDocument.defaultView;
if (this.searchTimeout) {
win.clearTimeout(this.searchTimeout);
}
var callback = this.doSearch.bind(this, searchBox);
this.searchTimeout = win.setTimeout(callback, searchDelay);
},
doSearch: function(searchBox) {
this.props.actions.onSearch(searchBox.value);
}
});
// Exports from this module
exports.SearchBox = SearchBox;
});

View File

@ -0,0 +1,79 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
define(function(require, exports, module) {
const React = require("react");
const { createFactories } = require("./reps/rep-utils");
const { Toolbar, ToolbarButton } = createFactories(require("./reps/toolbar"));
const DOM = React.DOM;
/**
* This template represents the 'Raw Data' panel displaying
* JSON as a text received from the server.
*/
var TextPanel = React.createClass({
displayName: "TextPanel",
getInitialState: function() {
return {};
},
render: function() {
return (
DOM.div({className: "textPanelBox"},
TextToolbar({actions: this.props.actions}),
DOM.div({className: "panelContent"},
DOM.pre({className: "data"},
this.props.data
)
)
)
);
}
});
/**
* This object represents a toolbar displayed within the
* 'Raw Data' panel.
*/
var TextToolbar = React.createFactory(React.createClass({
displayName: "TextToolbar",
render: function() {
return (
Toolbar({},
ToolbarButton({className: "btn prettyprint",onClick: this.onPrettify},
Locale.$STR("jsonViewer.PrettyPrint")
),
ToolbarButton({className: "btn save", onClick: this.onSave},
Locale.$STR("jsonViewer.Save")
),
ToolbarButton({className: "btn copy", onClick: this.onCopy},
Locale.$STR("jsonViewer.Copy")
)
)
)
},
// Commands
onPrettify: function(event) {
this.props.actions.onPrettify();
},
onSave: function(event) {
this.props.actions.onSaveJson();
},
onCopy: function(event) {
this.props.actions.onCopyJson();
},
}));
// Exports from this module
exports.TextPanel = TextPanel;
});

View File

@ -0,0 +1,309 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {Cu, Cc, Ci, components} = require("chrome");
const {Class} = require("sdk/core/heritage");
const {Unknown} = require("sdk/platform/xpcom");
const xpcom = require("sdk/platform/xpcom");
const Events = require("sdk/dom/events");
const Clipboard = require("sdk/clipboard");
loader.lazyRequireGetter(this, "NetworkHelper",
"devtools/shared/webconsole/network-helper");
loader.lazyRequireGetter(this, "JsonViewUtils",
"devtools/client/jsonview/utils");
const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
const childProcessMessageManager =
Cc["@mozilla.org/childprocessmessagemanager;1"].
getService(Ci.nsISyncMessageSender);
// Amount of space that will be allocated for the stream's backing-store.
// Must be power of 2. Used to copy the data stream in onStopRequest.
const SEGMENT_SIZE = Math.pow(2, 17);
const JSON_VIEW_MIME_TYPE = "application/vnd.mozilla.json.view";
const CONTRACT_ID = "@mozilla.org/streamconv;1?from=" + JSON_VIEW_MIME_TYPE + "&to=*/*";
const CLASS_ID = "{d8c9acee-dec5-11e4-8c75-1681e6b88ec1}";
// Localization
var jsonViewStrings = Services.strings.createBundle(
"chrome://browser/locale/devtools/jsonview.properties");
/**
* This object detects 'application/vnd.mozilla.json.view' content type
* and converts it into a JSON Viewer application that allows simple
* JSON inspection.
*
* Inspired by JSON View: https://github.com/bhollis/jsonview/
*/
var Converter = Class({
extends: Unknown,
interfaces: [
"nsIStreamConverter",
"nsIStreamListener",
"nsIRequestObserver"
],
get wrappedJSObject() this,
/**
* This component works as such:
* 1. asyncConvertData captures the listener
* 2. onStartRequest fires, initializes stuff, modifies the listener to match our output type
* 3. onDataAvailable transcodes the data into a UTF-8 string
* 4. onStopRequest gets the collected data and converts it, spits it to the listener
* 5. convert does nothing, it's just the synchronous version of asyncConvertData
*/
convert: function(aFromStream, aFromType, aToType, aCtxt) {
return aFromStream;
},
asyncConvertData: function(aFromType, aToType, aListener, aCtxt) {
this.listener = aListener;
},
onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) {
// From https://developer.mozilla.org/en/Reading_textual_data
var is = Cc["@mozilla.org/intl/converter-input-stream;1"].
createInstance(Ci.nsIConverterInputStream);
is.init(aInputStream, this.charset, -1,
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
// Seed it with something positive
var bytesRead = 1;
while (aCount) {
var str = {};
var bytesRead = is.readString(aCount, str);
if (!bytesRead) {
throw new Error("Stream converter failed to read the input stream!");
}
aCount -= bytesRead;
this.data += str.value;
}
},
onStartRequest: function(aRequest, aContext) {
this.data = "";
this.uri = aRequest.QueryInterface(Ci.nsIChannel).URI.spec;
// Sets the charset if it is available. (For documents loaded from the
// filesystem, this is not set.)
this.charset = aRequest.QueryInterface(Ci.nsIChannel).contentCharset || 'UTF-8';
this.channel = aRequest;
this.channel.contentType = "text/html";
this.channel.contentCharset = "UTF-8";
this.listener.onStartRequest(this.channel, aContext);
},
/**
* This should go something like this:
* 1. Make sure we have a unicode string.
* 2. Convert it to a Javascript object.
* 2.1 Removes the callback
* 3. Convert that to HTML? Or XUL?
* 4. Spit it back out at the listener
*/
onStopRequest: function(aRequest, aContext, aStatusCode) {
let headers = {
response: [],
request: []
}
let win = NetworkHelper.getWindowForRequest(aRequest);
let Locale = {
$STR: key => {
try {
return jsonViewStrings.GetStringFromName(key);
} catch (err) {
Cu.reportError(err);
}
}
};
JsonViewUtils.exportIntoContentScope(win, Locale, "Locale");
Events.once(win, "DOMContentLoaded", event => {
Cu.exportFunction(this.postChromeMessage.bind(this), win, {
defineAs: "postChromeMessage"
});
})
// The request doesn't have to be always nsIHttpChannel
// (e.g. in case of data: URLs)
if (aRequest instanceof Ci.nsIHttpChannel) {
aRequest.visitResponseHeaders({
visitHeader: function(name, value) {
headers.response.push({name: name, value: value});
}
});
aRequest.visitRequestHeaders({
visitHeader: function(name, value) {
headers.request.push({name: name, value: value});
}
});
}
let outputDoc = "";
try {
headers = JSON.stringify(headers);
outputDoc = this.toHTML(this.data, headers, this.uri);
} catch (e) {
Cu.reportError("JSON Viewer ERROR " + e);
outputDoc = this.toErrorPage(e, this.data, this.uri);
}
var storage = Cc["@mozilla.org/storagestream;1"].createInstance(Ci.nsIStorageStream);
storage.init(SEGMENT_SIZE, 0xffffffff, null);
var out = storage.getOutputStream(0);
var binout = Cc["@mozilla.org/binaryoutputstream;1"]
.createInstance(Ci.nsIBinaryOutputStream);
binout.setOutputStream(out);
binout.writeUtf8Z(outputDoc);
binout.close();
// We need to trim 4 bytes off the front (this could be underlying bug).
var trunc = 4;
var instream = storage.newInputStream(trunc);
// Pass the data to the main content listener
this.listener.onDataAvailable(this.channel, aContext, instream, 0,
instream.available());
this.listener.onStopRequest(this.channel, aContext, aStatusCode);
this.listener = null;
},
htmlEncode: function(t) {
return t !== null ? t.toString().replace(/&/g,"&amp;").
replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;") : '';
},
toHTML: function(json, headers, title) {
var themeClassName = "theme-" + JsonViewUtils.getCurrentTheme();
var baseUrl = "resource:///modules/devtools/client/jsonview/";
var theme = (themeClassName == "theme-light") ? "light" : "dark";
var themeUrl = '<link rel="stylesheet" type="text/css" ' +
'href="css/' + theme + '-theme.css">';
return '<!DOCTYPE html>\n' +
'<html><head><title>' + this.htmlEncode(title) + '</title>' +
'<base href="' + this.htmlEncode(baseUrl) + '">' +
'<link rel="stylesheet" type="text/css" href="css/main.css">' +
themeUrl +
'<script data-main="viewer-config" src="lib/require.js"></script>' +
'</head><body class="' + themeClassName + '">' +
'<div id="content"></div>' +
'<div id="json">' + this.htmlEncode(json) + '</div>' +
'<div id="headers">' + this.htmlEncode(headers) + '</div>' +
'</body></html>';
},
toErrorPage: function(error, data, uri) {
// Escape unicode nulls
data = data.replace("\u0000", "\uFFFD");
var errorInfo = error + "";
var output = '<div id="error">' + _('errorParsing')
if (errorInfo.message) {
output += '<div class="errormessage">' + errorInfo.message + '</div>';
}
output += '</div><div id="json">' + this.highlightError(data,
errorInfo.line, errorInfo.column) + '</div>';
return '<!DOCTYPE html>\n' +
'<html><head><title>' + this.htmlEncode(uri + ' - Error') + '</title>' +
'<base href="' + this.htmlEncode(self.data.url()) + '">' +
'</head><body>' +
output +
'</body></html>';
},
// Chrome <-> Content communication
postChromeMessage: function(type, args, objects) {
var value = args;
switch (type) {
case "copy":
Clipboard.set(value, "text");
break;
case "copy-headers":
this.copyHeaders(value);
break;
case "save":
childProcessMessageManager.sendAsyncMessage(
"devtools:jsonview:save", value);
}
},
copyHeaders: function(headers) {
var value = "";
var eol = (Services.appinfo.OS !== "WINNT") ? "\n" : "\r\n";
var responseHeaders = headers.response;
for (var i=0; i<responseHeaders.length; i++) {
var header = responseHeaders[i];
value += header.name + ": " + header.value + eol;
}
value += eol;
var requestHeaders = headers.request;
for (var i=0; i<requestHeaders.length; i++) {
var header = requestHeaders[i];
value += header.name + ": " + header.value + eol;
}
Clipboard.set(value, "text");
}
});
// Stream converter component definition
var service = xpcom.Service({
id: components.ID(CLASS_ID),
contract: CONTRACT_ID,
Component: Converter,
register: false,
unregister: false
});
function register() {
if (!xpcom.isRegistered(service)) {
xpcom.register(service);
return true;
}
return false;
}
function unregister() {
if (xpcom.isRegistered(service)) {
xpcom.unregister(service);
return true;
}
return false;
}
exports.JsonViewService = {
register: register,
unregister: unregister
}

View File

@ -0,0 +1,94 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
const {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
const {devtools} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {});
// Load JsonView services lazily.
XPCOMUtils.defineLazyGetter(this, "JsonViewService", function() {
const {JsonViewService} = devtools.require("devtools/client/jsonview/converter-child");
return JsonViewService;
});
XPCOMUtils.defineLazyGetter(this, "JsonViewSniffer", function() {
const {JsonViewSniffer} = devtools.require("devtools/client/jsonview/converter-sniffer");
return JsonViewSniffer;
});
// Constants
const JSON_VIEW_PREF = "devtools.jsonview.enabled";
/**
* Listen for 'devtools.jsonview.enabled' preference changes and
* register/unregister the JSON View XPCOM services as appropriate.
*/
function ConverterObserver() {
}
ConverterObserver.prototype = {
initialize: function() {
// Only the DevEdition has this feature available by default.
// Users need to manually flip 'devtools.jsonview.enabled' preference
// to have it available in other distributions.
if (this.isEnabled()) {
this.register();
}
Services.prefs.addObserver(JSON_VIEW_PREF, this, false);
Services.obs.addObserver(this, "xpcom-shutdown", false);
},
observe: function(subject, topic, data) {
switch (topic) {
case "xpcom-shutdown":
this.onShutdown();
break;
case "nsPref:changed":
this.onPrefChanged();
break;
};
},
onShutdown: function() {
Services.prefs.removeObserver(JSON_VIEW_PREF, observer);
Services.obs.removeObserver(observer, "xpcom-shutdown");
},
onPrefChanged: function() {
if (this.isEnabled()) {
this.register();
} else {
this.unregister();
}
},
register: function() {
JsonViewSniffer.register();
JsonViewService.register();
},
unregister: function() {
JsonViewSniffer.unregister();
JsonViewService.unregister();
},
isEnabled: function() {
return Services.prefs.getBoolPref(JSON_VIEW_PREF);
},
};
// Listen to JSON View 'enable' pref and perform dynamic
// registration or unregistration of the main application
// component.
var observer = new ConverterObserver();
observer.initialize();

View File

@ -0,0 +1,102 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {Cc, Ci, components} = require("chrome");
const xpcom = require("sdk/platform/xpcom");
const {Unknown} = require("sdk/platform/xpcom");
const {Class} = require("sdk/core/heritage");
const categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
loader.lazyRequireGetter(this, "NetworkHelper",
"devtools/shared/webconsole/network-helper");
// Constants
const JSON_TYPE = "application/json";
const CONTRACT_ID = "@mozilla.org/devtools/jsonview-sniffer;1";
const CLASS_ID = "{4148c488-dca1-49fc-a621-2a0097a62422}";
const JSON_VIEW_MIME_TYPE = "application/vnd.mozilla.json.view";
const JSON_VIEW_TYPE = "JSON View";
const CONTENT_SNIFFER_CATEGORY = "net-content-sniffers";
/**
* This component represents a sniffer (implements nsIContentSniffer
* interface) responsible for changing top level 'application/json'
* document types to: 'application/vnd.mozilla.json.view'.
*
* This internal type is consequently rendered by JSON View component
* that represents the JSON through a viewer interface.
*/
var Sniffer = Class({
extends: Unknown,
interfaces: [
"nsIContentSniffer",
],
get wrappedJSObject() this,
getMIMETypeFromContent: function(aRequest, aData, aLength) {
// JSON View is enabled only for top level loads only.
if (!NetworkHelper.isTopLevelLoad(aRequest)) {
return "";
}
if (aRequest instanceof Ci.nsIChannel) {
try {
if (aRequest.contentDisposition == Ci.nsIChannel.DISPOSITION_ATTACHMENT) {
return "";
}
} catch (e) {
// Channel doesn't support content dispositions
}
// Check the response content type and if it's application/json
// change it to new internal type consumed by JSON View.
if (aRequest.contentType == JSON_TYPE) {
return JSON_VIEW_MIME_TYPE;
}
}
return "";
}
});
var service = xpcom.Service({
id: components.ID(CLASS_ID),
contract: CONTRACT_ID,
Component: Sniffer,
register: false,
unregister: false
});
function register() {
if (!xpcom.isRegistered(service)) {
xpcom.register(service);
categoryManager.addCategoryEntry(CONTENT_SNIFFER_CATEGORY, JSON_VIEW_TYPE,
CONTRACT_ID, false, false);
return true;
}
return false;
}
function unregister() {
if (xpcom.isRegistered(service)) {
categoryManager.deleteCategoryEntry(CONTENT_SNIFFER_CATEGORY,
JSON_VIEW_TYPE, false)
xpcom.unregister(service);
return true;
}
return false;
}
exports.JsonViewSniffer = {
register: register,
unregister: unregister
}

View File

@ -0,0 +1,27 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
/******************************************************************************/
/* Dark Theme (copied from themes/dark-theme.css) */
:root {
--theme-body-background: #14171a;
--theme-tab-toolbar-background: #252c33;
--theme-toolbar-background: #343c45;
--theme-selection-background: #1d4f73;
--theme-splitter-color: black;
--theme-selection-color: #f5f7fa;
--theme-comment: #757873;
--theme-body-color: #8fa1b2;
--theme-body-color-alt: #b6babf;
--theme-content-color1: #a9bacb;
--theme-highlight-green: #70bf53;
--theme-highlight-blue: #46afe3;
--theme-highlight-orange: #d96629;
--theme-highlight-bluegrey: #5e88b0;
}

View File

@ -0,0 +1,152 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
.domTable {
font-size: 11px;
font-family: Lucida Grande, Tahoma, sans-serif;
line-height: 15px;
width: 100%;
}
.domTable > tbody > tr > td {
border-bottom: 1px solid #EFEFEF;
}
.hidden {
display: none;
}
.memberLabelCell {
padding: 2px 0 2px 0px;
vertical-align: top;
}
.memberValueCell {
padding: 2px 0 2px 5px;
overflow: hidden;
}
.memberLabel {
cursor: default;
overflow: hidden;
padding-left: 18px;
white-space: nowrap;
}
.memberLabelPrefix {
color: gray;
margin-right: 3px;
font-weight: normal;
}
.memberValueIcon > div {
width: 15px;
}
/******************************************************************************/
/* Read Only Properties */
.memberValueCell.readOnly {
opacity: 0.5;
}
.memberValueIcon.readOnly {
background: url("read-only-prop.svg") no-repeat;
background-position: 4px 4px;
background-size: 10px 10px;
}
/******************************************************************************/
.memberRow.hasChildren > .memberLabelCell > .memberLabel:hover,
.memberRow.cropped > .memberLabelCell > .memberLabel:hover {
cursor: pointer;
color: blue;
text-decoration: underline;
}
.memberRow:hover {
background-color: #EFEFEF;
}
.panelNode-dom .memberRow td,
.panelNode-domSide .memberRow td {
border-bottom: 1px solid #EFEFEF;
}
/******************************************************************************/
.userLabel,
.userClassLabel,
.userFunctionLabel {
font-weight: bold;
}
.userLabel {
color: #000000;
}
.userClassLabel {
color: #E90000;
}
.userFunctionLabel {
color: #025E2A;
}
.domLabel {
color: #000000;
}
.domClassLabel {
color: #E90000;
}
.domFunctionLabel {
color: #025E2A;
}
.ordinalLabel {
color: SlateBlue;
font-weight: bold;
}
/******************************************************************************/
/* Twisties */
.memberRow.hasChildren > .memberLabelCell > .memberLabel,
.memberRow.cropped > .memberLabelCell > .memberLabel {
background-image: url(twisty-closed.svg);
background-repeat: no-repeat;
background-position: 2px calc(0.5em - 3px);
min-height: 12px;
}
.memberRow.hasChildren.opened > .memberLabelCell > .memberLabel,
.memberRow.cropped.opened > .memberLabelCell > .memberLabel {
background-image: url(twisty-open.svg);
background-repeat: no-repeat;
min-height: 12px;
}
/******************************************************************************/
/* Layout support */
.memberChildren {
padding-left: 16px;
}
.memberLabelCell,
.memberValueCell {
display: table-cell;
}
.memberLabelCell {
min-width: 30px;
}
.memberRow:hover {
background-color: transparent !important;
}

View File

@ -0,0 +1,44 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
/******************************************************************************/
/* General */
body {
background-color: white;
padding: 0;
margin: 0;
overflow: hidden;
}
*:focus {
outline: none !important;
}
#content {
height: 100%;
}
pre {
background-color: white;
border: none;
}
#json,
#headers {
display: none;
}
/******************************************************************************/
/* Dark Theme */
body.theme-dark {
color: var(--theme-body-color);
background-color: var(--theme-body-background);
}
.theme-dark pre {
background-color: var(--theme-body-background);
}

View File

@ -0,0 +1,79 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
/******************************************************************************/
/* Headers Panel */
.headersPanelBox {
height: 100%;
font-family: Lucida Grande, Tahoma, sans-serif;
font-size: 11px;
}
.headersPanelBox .netInfoHeadersTable {
overflow: auto;
height: 100%;
line-height: 12px;
}
.headersPanelBox .netHeadersGroup {
padding: 10px;
}
.headersPanelBox .netInfoHeadersGroup {
margin-bottom: 10px;
border-bottom: 1px solid #D7D7D7;
padding-top: 8px;
padding-bottom: 4px;
font-family: Lucida Grande, Tahoma, sans-serif;
font-weight: bold;
color: #565656;
}
.headersPanelBox .netHeader.twisty {
background-image: url(twisty-open.svg);
background-repeat: no-repeat;
min-height: 12px;
background-position: 2px 50%;
}
.headersPanelBox .netHeader {
cursor: pointer;
padding-left: 17px;
position: static;
-moz-user-select: none;
}
.headersPanelBox .netInfoParamValue code {
display: block;
color: #18191A;
font-size: 11px;
word-wrap: break-word;
}
.headersPanelBox .netInfoParamName {
padding: 2px 10px 0 0;
font-family: Lucida Grande, Tahoma, sans-serif;
font-weight: bold;
vertical-align: top;
text-align: right;
white-space: nowrap;
}
/******************************************************************************/
/* Dark Theme */
.theme-dark .headersPanelBox .netInfoParamName {
color: var(--theme-highlight-blue);
}
.theme-dark .headersPanelBox .netInfoParamValue code {
color: var(--theme-highlight-orange);
}
.theme-dark .headersPanelBox .netInfoHeadersGroup {
color: var(--theme-body-color-alt);
}

View File

@ -0,0 +1,16 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
/******************************************************************************/
/* JSON Panel */
.jsonParseError {
font-size: 12px;
font-family: Lucida Grande, Tahoma, sans-serif;
line-height: 15px;
width: 100%;
padding: 10px;
color: red;
}

View File

@ -0,0 +1,27 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
/******************************************************************************/
/* Light Theme Constants (copied from themes/light-theme.css) */
:root {
--theme-body-background: #fcfcfc;
--theme-tab-toolbar-background: #ebeced;
--theme-toolbar-background: #f0f1f2;
--theme-selection-background: #4c9ed9;
--theme-splitter-color: #aaaaaa;
--theme-selection-color: #f5f7fa;
--theme-comment: #757873;
--theme-body-color: #18191a;
--theme-body-color-alt: #585959;
--theme-content-color1: #292e33;
--theme-highlight-green: #2cbb0f;
--theme-highlight-blue: #0088cc;
--theme-highlight-orange: #f13c00;
--theme-highlight-bluegrey: #0072ab;
}

View File

@ -0,0 +1,37 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
@import "general.css";
@import "reps.css";
@import "dom-tree.css";
@import "search-box.css";
@import "tabs.css";
@import "toolbar.css";
@import "json-panel.css";
@import "text-panel.css";
@import "headers-panel.css";
/******************************************************************************/
/* Panel Content */
.panelContent {
overflow-y: auto;
}
/******************************************************************************/
/* Theme Firebug */
.theme-firebug .panelContent {
height: calc(100% - 30px);
}
/******************************************************************************/
/* Theme Light & Theme Dark*/
.theme-dark .panelContent,
.theme-light .panelContent {
height: calc(100% - 27px);
}

View File

@ -0,0 +1,25 @@
# -*- 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/.
DevToolsModules(
'dark-theme.css',
'dom-tree.css',
'general.css',
'headers-panel.css',
'json-panel.css',
'light-theme.css',
'main.css',
'read-only-prop.svg',
'reps.css',
'search-box.css',
'search.svg',
'tabs.css',
'text-panel.css',
'toolbar.css',
'twisty-closed.svg',
'twisty-open.svg'
)

View File

@ -0,0 +1,256 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- 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/. -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width="12"
height="12"
id="svg2">
<defs
id="defs4">
<linearGradient
id="linearGradient3892">
<stop
id="stop3894"
style="stop-color:#787878;stop-opacity:1"
offset="0" />
<stop
id="stop3896"
style="stop-color:#b4b4b4;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient3765">
<stop
id="stop3767"
style="stop-color:#505050;stop-opacity:1"
offset="0" />
<stop
id="stop3769"
style="stop-color:#787878;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient3757">
<stop
id="stop3759"
style="stop-color:#c8c8c8;stop-opacity:1"
offset="0" />
<stop
id="stop3761"
style="stop-color:#dcdcdc;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient3765-6">
<stop
id="stop3767-0"
style="stop-color:#a0a0a0;stop-opacity:1"
offset="0" />
<stop
id="stop3769-4"
style="stop-color:#c8c8c8;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
x1="11.376831"
y1="1052.0852"
x2="4.5592546"
y2="1040.6658"
id="linearGradient3830"
xlink:href="#linearGradient3757"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.87012989,0,0,0.82456145,1.0389611,183.57212)" />
<linearGradient
x1="8.8415442"
y1="1053.3849"
x2="1.9174434"
y2="1041.9227"
id="linearGradient3832"
xlink:href="#linearGradient3765-6"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.87012989,0,0,0.82456145,1.0389611,183.57212)" />
<linearGradient
x1="8.6370001"
y1="4.3111062"
x2="6.3403625"
y2="0.58274388"
id="linearGradient3861"
xlink:href="#linearGradient3757"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.89600004,0,0,0.97745455,0.83199985,0.9945)" />
<linearGradient
x1="7.1882658"
y1="5.0780835"
x2="4.9555426"
y2="1.392331"
id="linearGradient3866"
xlink:href="#linearGradient3765-6"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.89600004,0,0,0.97745455,0.83199985,0.9945)" />
<linearGradient
x1="9.3919191"
y1="12.115811"
x2="7.4015098"
y2="7.4140091"
id="linearGradient3909"
xlink:href="#linearGradient3892"
gradientUnits="userSpaceOnUse" />
<linearGradient
x1="8.5397177"
y1="12.497831"
x2="6.6080809"
y2="7.825417"
id="linearGradient3917"
xlink:href="#linearGradient3765"
gradientUnits="userSpaceOnUse" />
<linearGradient
x1="8.5397177"
y1="12.497831"
x2="6.6080809"
y2="7.825417"
id="linearGradient3039"
xlink:href="#linearGradient3765"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.71428573,0,0,0.71492245,0.28571425,0.27617311)" />
<linearGradient
x1="9.3919191"
y1="12.115811"
x2="7.4015098"
y2="7.4140091"
id="linearGradient3041"
xlink:href="#linearGradient3892"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.71428573,0,0,0.71492245,0.28571425,0.27617311)" />
<linearGradient
x1="11.376831"
y1="1052.0852"
x2="4.5592546"
y2="1040.6658"
id="linearGradient3044"
xlink:href="#linearGradient3757"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.62152136,0,0,0.58949749,1.0278293,-609.4026)" />
<linearGradient
x1="8.8415442"
y1="1053.3849"
x2="1.9174434"
y2="1041.9227"
id="linearGradient3046"
xlink:href="#linearGradient3765-6"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.62152136,0,0,0.58949749,1.0278293,-609.4026)" />
<linearGradient
x1="8.6370001"
y1="4.3111062"
x2="6.3403625"
y2="0.58274388"
id="linearGradient3049"
xlink:href="#linearGradient3757"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.64000004,0,0,0.6988042,0.87999987,0.98716349)" />
<linearGradient
x1="7.1882658"
y1="5.0780835"
x2="4.9555426"
y2="1.392331"
id="linearGradient3051"
xlink:href="#linearGradient3765-6"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.64000004,0,0,0.6988042,0.87999987,0.98716349)" />
<linearGradient
x1="8.6370001"
y1="4.3111062"
x2="6.3403625"
y2="0.58274388"
id="linearGradient3826"
xlink:href="#linearGradient3757"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.64000004,0,0,0.6988042,0.87999987,0.98716349)" />
<linearGradient
x1="7.1882658"
y1="5.0780835"
x2="4.9555426"
y2="1.392331"
id="linearGradient3828"
xlink:href="#linearGradient3765-6"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.64000004,0,0,0.6988042,0.87999987,0.98716349)" />
<linearGradient
x1="11.376831"
y1="1052.0852"
x2="4.5592546"
y2="1040.6658"
id="linearGradient3831"
xlink:href="#linearGradient3757"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.62152136,0,0,0.58949749,1.0278293,-609.4026)" />
<linearGradient
x1="8.8415442"
y1="1053.3849"
x2="1.9174434"
y2="1041.9227"
id="linearGradient3833"
xlink:href="#linearGradient3765-6"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.62152136,0,0,0.58949749,1.0278293,-609.4026)" />
<linearGradient
x1="8.5397177"
y1="12.497831"
x2="6.6080809"
y2="7.825417"
id="linearGradient3835"
xlink:href="#linearGradient3765"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.71428573,0,0,0.71492245,0.28571425,0.27617311)" />
<linearGradient
x1="9.3919191"
y1="12.115811"
x2="7.4015098"
y2="7.4140091"
id="linearGradient3837"
xlink:href="#linearGradient3892"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.71428573,0,0,0.71492245,0.28571425,0.27617311)" />
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="matrix(1.1910164,0,0,1.1910639,-1.146234,-1.1462857)"
id="g3821">
<path
d="m 6.0000001,1.2145088 c -1.6317576,0 -2.9446627,1.2860444 -2.9910715,2.9043725 0.1136269,-0.018496 0.2381347,-0.044683 0.3571429,-0.044683 l 0.9375,0 c 0.082361,-0.8799332 0.7978203,-1.6532581 1.6964286,-1.6532581 0.8986083,0 1.6140679,0.7733249 1.6964286,1.6532581 l 0.9375,0 c 0.1190079,0 0.2435157,0.026187 0.3571429,0.044683 C 8.944663,2.5005532 7.6317573,1.2145088 6.0000001,1.2145088 z"
id="path3773"
style="fill:url(#linearGradient3826);fill-opacity:1;stroke:url(#linearGradient3828);stroke-width:0.50376141;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<rect
width="9.5714283"
height="6.7202706"
rx="1.679238"
ry="1.6791711"
x="1.2142856"
y="4.0652847"
id="rect2987-9"
style="fill:url(#linearGradient3831);fill-opacity:1;stroke:url(#linearGradient3833);stroke-width:0.50376141;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
d="m 6.0000001,5.5040435 c -0.6706315,0 -1.2053572,0.5352023 -1.2053572,1.2064317 0,0.5619236 0.3753047,1.0226472 0.8928572,1.1617489 l 0,1.4745276 0.625,0 0,-1.4745276 C 6.8300525,7.7331224 7.2053573,7.2723988 7.2053573,6.7104752 c 0,-0.6712294 -0.5347257,-1.2064317 -1.2053572,-1.2064317 z"
id="path3898"
style="fill:url(#linearGradient3835);fill-opacity:1;stroke:url(#linearGradient3837);stroke-width:0.33584094;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@ -0,0 +1,211 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
.objectLink:hover {
cursor: pointer;
text-decoration: underline;
}
/******************************************************************************/
.inline {
display: inline;
white-space: normal;
}
.objectBox-object {
font-family: Lucida Grande, sans-serif;
font-weight: bold;
color: DarkGreen;
white-space: pre-wrap;
}
.objectBox-string,
.objectBox-text,
.objectBox-number,
.objectLink-element,
.objectLink-textNode,
.objectLink-function,
.objectBox-stackTrace,
.objectLink-profile,
.objectBox-table {
font-family: monospace;
}
.objectBox-string,
.objectBox-text,
.objectLink-textNode,
.objectBox-table {
white-space: pre-wrap;
}
.objectBox-number,
.objectLink-styleRule,
.objectLink-element,
.objectLink-textNode {
color: #000088;
}
.objectBox-string {
color: #FF0000;
}
.objectLink-function,
.objectBox-stackTrace,
.objectLink-profile {
color: DarkGreen;
}
.objectBox-null,
.objectBox-undefined,
.objectBox-hint,
.logRowHint {
font-style: italic;
color: #787878;
}
.objectBox-scope {
color: #707070;
}
.objectBox-optimizedAway {
color: #909090;
}
.objectLink-sourceLink {
position: absolute;
right: 4px;
top: 2px;
padding-left: 8px;
font-family: Lucida Grande, sans-serif;
font-weight: bold;
color: #0000FF;
}
.objectLink-sourceLink > .systemLink {
float: right;
color: #FF0000;
}
/******************************************************************************/
.objectLink-event,
.objectLink-eventLog,
.objectLink-regexp,
.objectLink-object,
.objectLink-Date {
font-family: Lucida Grande, sans-serif;
font-weight: bold;
color: DarkGreen;
white-space: pre-wrap;
}
/******************************************************************************/
.objectLink-object .nodeName,
.objectLink-NamedNodeMap .nodeName,
.objectLink-NamedNodeMap .objectEqual,
.objectLink-NamedNodeMap .arrayLeftBracket,
.objectLink-NamedNodeMap .arrayRightBracket,
.objectLink-Attr .attrEqual,
.objectLink-Attr .attrTitle {
color: rgb(0, 0, 136)
}
.objectLink-object .nodeName {
font-weight: normal;
}
/******************************************************************************/
.objectLeftBrace,
.objectRightBrace,
.objectEqual,
.objectComma,
.arrayLeftBracket,
.arrayRightBracket,
.arrayComma {
font-family: monospace;
}
.objectLeftBrace,
.objectRightBrace,
.arrayLeftBracket,
.arrayRightBracket {
cursor: pointer;
font-weight: bold;
}
.objectLeftBrace,
.arrayLeftBracket {
margin-right: 4px;
}
.objectRightBrace,
.arrayRightBracket {
margin-left: 4px;
}
/******************************************************************************/
/* Cycle reference*/
.objectLink-Reference {
font-family: monospace;
font-weight: bold;
color: rgb(102, 102, 255);
}
.objectBox-array > .objectTitle {
font-weight: bold;
color: DarkGreen;
}
/******************************************************************************/
.caption {
font-family: Lucida Grande, Tahoma, sans-serif;
font-weight: bold;
color: #444444;
}
/******************************************************************************/
/* Light Theme & Dark Theme */
.theme-dark .domLabel,
.theme-light .domLabel {
color: var(--theme-highlight-bluegrey);
}
.theme-dark .objectBox-number,
.theme-light .objectBox-number {
color: var(--theme-highlight-green);
}
.theme-dark .objectBox-string,
.theme-light .objectBox-string {
color: var(--theme-highlight-orange)
}
.theme-dark .objectBox-null,
.theme-dark .objectBox-undefined,
.theme-light .objectBox-null,
.theme-light .objectBox-undefined {
font-style: normal;
color: var(--theme-comment);
}
.theme-dark .objectBox-object,
.theme-light .objectBox-object {
font-family: Lucida Grande, sans-serif;
font-weight: normal;
color: var(--theme-highlight-bluegrey);
white-space: pre-wrap;
}
.theme-dark .caption,
.theme-light .caption {
font-family: Lucida Grande, Tahoma, sans-serif;
font-weight: normal;
color: var(--theme-highlight-bluegrey);
}

View File

@ -0,0 +1,46 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
/******************************************************************************/
/* Search Box */
.searchBox {
height: 18px;
font-size: 12px;
margin-top: 0;
border: 1px solid rgb(170, 188, 207);
width: 200px;
position: fixed;
right: 5px;
background-image: url("search.svg");
background-repeat: no-repeat;
background-position: 2px center;
padding-left: 20px;
}
/******************************************************************************/
/* Light Theme & Dark Theme*/
.theme-dark .searchBox,
.theme-light .searchBox {
border: 1px solid rgb(170, 170, 170);
background-image: url("chrome://browser/skin/devtools/magnifying-glass-light.png");
background-position: 8px center;
border-radius: 2px;
padding-left: 25px;
margin-top: 1px;
height: 16px;
font-style: italic;
}
/******************************************************************************/
/* Dark Theme */
.theme-dark .searchBox {
background-color: rgba(24, 29, 32, 1);
color: rgba(184, 200, 217, 1);
border-color: var(--theme-splitter-color);
background-image: url("chrome://browser/skin/devtools/magnifying-glass.png");
}

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- 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/. -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width="16"
height="16"
id="svg2">
<defs
id="defs4">
<linearGradient
id="linearGradient3841">
<stop
id="stop3843"
style="stop-color:#427dc2;stop-opacity:1"
offset="0" />
<stop
id="stop3845"
style="stop-color:#5e9fce;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient3795">
<stop
id="stop3797"
style="stop-color:#2f5d93;stop-opacity:1"
offset="0" />
<stop
id="stop3799"
style="stop-color:#3a87bd;stop-opacity:0.99215686"
offset="1" />
</linearGradient>
<filter
x="-0.1195599"
y="-0.12044335"
width="1.2391198"
height="1.2408867"
color-interpolation-filters="sRGB"
id="filter2984">
<feGaussianBlur
id="feGaussianBlur2986"
stdDeviation="0.63671875" />
</filter>
<linearGradient
x1="4.0935063"
y1="13.423457"
x2="4.0935063"
y2="2.742672"
id="linearGradient3800"
xlink:href="#linearGradient3841"
gradientUnits="userSpaceOnUse" />
<linearGradient
x1="8.7112017"
y1="13.579539"
x2="8.7112017"
y2="2.5663419"
id="linearGradient3808"
xlink:href="#linearGradient3795"
gradientUnits="userSpaceOnUse" />
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<path
d="m 10.140619,1.656256 c -2.3511382,0 -4.2500001,1.898862 -4.2500001,4.2500004 0,0.751994 0.189088,1.449383 0.53125,2.0625 l -4.8125,4.8124996 1.5625001,1.5625 4.7812499,-4.7812496 c 0.6402543,0.38528 1.3858221,0.5937496 2.1875001,0.5937496 2.351138,0 4.25,-1.8988616 4.25,-4.2499996 0,-2.3511384 -1.898862,-4.2500004 -4.25,-4.2500004 z m 0,1.53125 c 1.503797,0 2.71875,1.214953 2.71875,2.7187504 0,1.503798 -1.214953,2.71875 -2.71875,2.71875 -1.5037975,0 -2.7187501,-1.214952 -2.7187501,-2.71875 0,-1.5037974 1.2149526,-2.7187504 2.7187501,-2.7187504 z"
id="path3014-7"
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;filter:url(#filter2984)" />
<path
d="M 10,2 C 7.7908609,2 6,3.7908609 6,6 6,6.8284272 6.2562027,7.6115959 6.6875,8.25 L 1.8125,13.125 2.875,14.1875 7.75,9.3125 C 8.3884041,9.7437973 9.1715728,10 10,10 12.209139,10 14,8.2091391 14,6 14,3.7908609 12.209139,2 10,2 z m 0,1 c 1.656854,0 3,1.3431458 3,3 0,1.6568542 -1.343146,3 -3,3 C 8.3431458,9 7,7.6568542 7,6 7,4.3431458 8.3431458,3 10,3 z"
id="path2994"
style="fill:url(#linearGradient3800);fill-opacity:1;stroke:url(#linearGradient3808);stroke-width:0.60000002;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,205 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
/******************************************************************************/
/* Tabs General Styles */
.tabs {
height: 100%;
}
.tabs .tabs-navigation {
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 14px;
border-bottom-color: rgb(170, 188, 207);
}
.tabs .tabs-menu {
display: table;
list-style: none;
padding: 0;
margin: 0;
}
.tabs .tabs-menu-item {
float: left;
}
.tabs .tabs-menu-item a {
display: block;
color: #A9A9A9;
padding: 4px 8px;
}
.tabs .tabs-menu-item a {
border: 1px solid transparent;
text-decoration: none;
}
.tabs .tab-panel {
background-color: white;
}
.tabs .tab-panel > DIV,
.tabs .tab-panel > DIV > DIV {
height: 100%;
}
/******************************************************************************/
/* Firebug Theme */
.theme-firebug .tabs {
background-color: rgb(219, 234, 249);
background-image: linear-gradient(rgba(253, 253, 253, 0.2), rgba(253, 253, 253, 0));
}
.theme-firebug .tabs .tabs-navigation {
padding-top: 3px;
padding-left: 3px;
height: 27px;
border-bottom: 1px solid rgb(170, 188, 207);
}
.theme-firebug .tabs .tab-panel {
height: calc(100% - 31px); /* minus the height of the tab bar */
}
.theme-firebug .tabs .tabs-menu-item {
position: relative;
}
.theme-firebug .tabs .tabs-menu-item a {
padding: 5px 8px 4px 8px;;
font-weight: bold;
color: #565656;
border-radius: 4px 4px 0 0;
}
.theme-firebug .tabs .tabs-menu-item.is-active a,
.theme-firebug .tabs .tabs-menu-item.is-active a:focus {
background-color: rgb(247, 251, 254);
border: 1px solid rgb(170, 188, 207);
border-bottom-color: transparent;
}
.theme-firebug .tabs .tabs-menu-item:hover a {
border: 1px solid #C8C8C8;
border-bottom: 1px solid transparent;
background-color: transparent !important;
}
.theme-firebug .tabs .tabs-menu-item.is-active:hover a {
border: 1px solid rgb(170, 188, 207) !important;
background-color: rgb(247, 251, 254) !important;
border-bottom-color: transparent !important;
}
/******************************************************************************/
/* Light Theme */
.theme-dark .tabs,
.theme-light .tabs {
background: var(--theme-tab-toolbar-background);
}
.theme-dark .tabs .tabs-navigation,
.theme-light .tabs .tabs-navigation {
border-bottom: 1px solid var(--theme-splitter-color);
box-shadow: 0 -2px 0 rgba(170, 170, 170,.1) inset;
height: 24px;
font-size: 12px;
}
.theme-dark .tabs .tab-panel,
.theme-light .tabs .tab-panel {
height: calc(100% - 24px); /* minus the height of the tab bar */
}
.theme-dark .tabs .tabs-menu-item,
.theme-light .tabs .tabs-menu-item {
margin: 0;
padding: 0;
border-style: solid;
border-width: 0;
-moz-border-start-width: 1px;
border-color: var(--theme-splitter-color);
}
.theme-dark .tabs .tabs-menu-item a,
.theme-light .tabs .tabs-menu-item a {
color: var(--theme-content-color1);
}
.theme-dark .tabs .tabs-menu-item a:hover,
.theme-dark .tabs .tabs-menu-item a,
.theme-light .tabs .tabs-menu-item a:hover,
.theme-light .tabs .tabs-menu-item a {
border: none !important;
background-color: transparent !important;
padding: 5px 15px;
}
.theme-dark .tabs .tabs-menu-item:hover,
.theme-light .tabs .tabs-menu-item:hover {
background-color: rgba(170,170,170,.2);
}
.theme-dark .tabs .tabs-menu-item.is-active,
.theme-dark .tabs .tabs-menu-item.is-active:hover,
.theme-light .tabs .tabs-menu-item.is-active,
.theme-light .tabs .tabs-menu-item.is-active:hover {
background-color: var(--theme-selection-background);
}
.theme-dark .tabs .tabs-menu-item.is-active a,
.theme-dark .tabs .tabs-menu-item.is-active:hover a,
.theme-light .tabs .tabs-menu-item.is-active a,
.theme-light .tabs .tabs-menu-item.is-active:hover a {
color: var(--theme-selection-color);
}
.theme-dark .tabs .tabs-menu-item:active:hover,
.theme-light .tabs .tabs-menu-item:active:hover {
background-color: rgba(170,170,170,.4);
}
.theme-dark .tabs .tabs-menu-item.is-active,
.theme-light .tabs .tabs-menu-item.is-active {
box-shadow: 0 2px 0 #d7f1ff inset,
0 8px 3px -5px #2b82bf inset,
0 -2px 0 rgba(0,0,0,.06) inset;
}
/******************************************************************************/
/* Dark Theme */
.theme-dark .tabs .tabs-navigation {
box-shadow: 0px -2px 0px rgba(0, 0, 0, 0.1) inset;
}
.theme-dark .tabs .tabs-menu-item a {
color: #CED3D9;
}
.theme-dark .tabs .tabs-menu-item a:hover,
.theme-dark .tabs .tabs-menu-item a {
border: none !important;
background-color: transparent !important;
padding: 5px 15px;
}
.theme-dark .tabs .tabs-menu-item:active:hover {
background-color: hsla(206,37%,4%,.4);
}
.theme-dark .tabs .tabs-menu-item.is-active {
box-shadow: 0px 2px 0px #D7F1FF inset,
0px 8px 3px -5px #2B82BF inset,
0px -2px 0px rgba(0, 0, 0, 0.2) inset;
}
.theme-dark .tabs .tab-panel {
background-color: var(--theme-body-background);
}

View File

@ -0,0 +1,29 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
/******************************************************************************/
/* Text Panel */
.textPanelBox {
height: 100%;
}
.textPanelBox .data {
font-size: 11px;
font-family: monospace;
overflow: auto;
height: 100%;
}
.textPanelBox pre {
margin: 0;
}
/******************************************************************************/
/* Dark Theme */
.theme-dark .textPanelBox {
color: var(--theme-content-color1);
}

View File

@ -0,0 +1,94 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
/******************************************************************************/
/* Toolbar */
.toolbar {
line-height: 20px;
font-size: 12px;
height: 22px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
padding: 4px 0 3px 0;
}
.toolbar .btn {
margin-left: 5px;
background-color: #E6E6E6;
border: 1px solid rgb(204, 204, 204);
text-decoration: none;
display: inline-block;
text-align: center;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
-moz-user-select: none;
padding: 0 2px 1px 2px;
}
.toolbar .btn::-moz-focus-inner {
border: 1px solid transparent;
}
/******************************************************************************/
/* Firebug Theme */
.theme-firebug .toolbar {
border-bottom: 1px solid rgb(170, 188, 207);
background-color: rgb(219, 234, 249) !important;
background-image: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.2));
}
.theme-firebug .toolbar .btn {
border-radius: 2px;
color: #141414;
background-color: white;
}
.theme-firebug .toolbar .btn:hover {
color: #333;
background-color: #e6e6e6;
border-color: #adadad;
}
.theme-firebug .toolbar .btn:active {
background-image: none;
outline: 0;
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
}
/******************************************************************************/
/* Light Theme & Dark Theme*/
.theme-dark .toolbar,
.theme-light .toolbar {
background-color: var(--theme-toolbar-background);
border-bottom: 1px solid var(--theme-splitter-color);
padding: 1px;
padding-left: 2px;
}
.theme-dark .toolbar .btn,
.theme-light .toolbar .btn {
min-width: 78px;
min-height: 18px;
color: var(--theme-content-color1);
text-shadow: none;
margin: 1px 2px 1px 2px;
border: none;
border-radius: 0;
background-color: rgba(170, 170, 170, .2); /* Splitter */
transition: background 0.05s ease-in-out;
}
.theme-dark .toolbar .btn:hover,
.theme-light .toolbar .btn:hover {
background: rgba(170, 170, 170, .3); /* Splitters */
}
.theme-dark .toolbar .btn:not([disabled]):hover:active,
.theme-light .toolbar .btn:not([disabled]):hover:active {
background: rgba(170, 170, 170, .4); /* Splitters */
}

View File

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- 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/. -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width="11"
height="11"
id="svg2">
<defs
id="defs4">
<linearGradient
id="linearGradient3792">
<stop
id="stop3795"
style="stop-color:#c3baaa;stop-opacity:1"
offset="0" />
<stop
id="stop3797"
style="stop-color:#ffffff;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
x1="6.0530181"
y1="7.092885"
x2="2.8882971"
y2="1.7999334"
id="linearGradient3799"
xlink:href="#linearGradient3792"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0256411,0,0,1.0256411,-0.11538478,1.8846152)" />
<linearGradient
x1="6.0530181"
y1="7.092885"
x2="2.8882971"
y2="1.7999334"
id="linearGradient2992"
xlink:href="#linearGradient3792"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0256411,0,0,1.0256411,-0.11538478,1.8846152)" />
<linearGradient
x1="6.0530181"
y1="7.092885"
x2="2.8882971"
y2="1.7999334"
id="linearGradient2996"
xlink:href="#linearGradient3792"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0256411,0,0,1.0256411,0.88461522,0.8846152)" />
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<rect
width="8"
height="8"
rx="1"
ry="1"
x="1.5"
y="1.5"
id="rect3022"
style="fill:url(#linearGradient2996);fill-opacity:1;stroke:#7898b5;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
d="M 5,3 5,5 3,5 3,6 5,6 5,8 6,8 6,6 8,6 8,5 6,5 6,3 5,3 z"
id="rect3801"
style="fill:#000000;fill-opacity:1;stroke:none" />
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- 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/. -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width="11"
height="11"
id="svg2">
<defs
id="defs4">
<linearGradient
id="linearGradient3792">
<stop
id="stop3795"
style="stop-color:#c3baaa;stop-opacity:1"
offset="0" />
<stop
id="stop3797"
style="stop-color:#ffffff;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
x1="6.0530181"
y1="7.092885"
x2="2.8882971"
y2="1.7999334"
id="linearGradient3799"
xlink:href="#linearGradient3792"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0256411,0,0,1.0256411,-0.11538478,1.8846152)" />
<linearGradient
x1="6.0530181"
y1="7.092885"
x2="2.8882971"
y2="1.7999334"
id="linearGradient2992"
xlink:href="#linearGradient3792"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0256411,0,0,1.0256411,-0.11538478,1.8846152)" />
<linearGradient
x1="6.0530181"
y1="7.092885"
x2="2.8882971"
y2="1.7999334"
id="linearGradient2996"
xlink:href="#linearGradient3792"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0256411,0,0,1.0256411,0.88461522,0.8846152)" />
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<rect
width="8"
height="8"
rx="1"
ry="1"
x="1.5"
y="1.5"
id="rect3022"
style="fill:url(#linearGradient2996);fill-opacity:1;stroke:#7898b5;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<rect
width="5"
height="1"
x="3"
y="5"
id="rect3801"
style="fill:#000000;fill-opacity:1;stroke:none" />
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

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