Merge from mozilla-central.
Merge from mozilla-central.
--- a/Makefile.in
+++ b/Makefile.in
@@ -48,16 +48,19 @@ endif
ifdef MOZ_MEMORY
tier_base_dirs += memory/mozjemalloc
ifdef MOZ_JEMALLOC
tier_base_dirs += memory/jemalloc
endif
tier_base_dirs += memory/build
endif
+ifndef MOZ_NATIVE_ZLIB
+tier_base_dirs += modules/zlib
+endif
tier_base_dirs += \
mozglue \
memory/mozalloc \
$(NULL)
endif
ifdef COMPILE_ENVIRONMENT
include $(topsrcdir)/$(MOZ_BUILD_APP)/build.mk
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -577,17 +577,17 @@ nsRoleMapEntry nsARIAMap::gEmptyRoleMap
kNoReqStates
};
/**
* Universal (Global) states:
* The following state rules are applied to any accessible element,
* whether there is an ARIA role or not:
*/
-EStateRule nsARIAMap::gWAIUnivStateMap[] = {
+static const EStateRule sWAIUnivStateMap[] = {
eARIABusy,
eARIADisabled,
eARIAExpanded, // Currently under spec review but precedent exists
eARIAHasPopup, // Note this is technically a "property"
eARIAInvalid,
eARIARequired, // XXX not global, Bug 553117
eARIANone
};
@@ -630,17 +630,18 @@ nsAttributeCharacteristics nsARIAMap::gW
{&nsGkAtoms::aria_setsize, ATTR_BYPASSOBJ }, /* handled via groupPosition */
{&nsGkAtoms::aria_sort, ATTR_VALTOKEN },
{&nsGkAtoms::aria_valuenow, ATTR_BYPASSOBJ },
{&nsGkAtoms::aria_valuemin, ATTR_BYPASSOBJ },
{&nsGkAtoms::aria_valuemax, ATTR_BYPASSOBJ },
{&nsGkAtoms::aria_valuetext, ATTR_BYPASSOBJ }
};
-PRUint32 nsARIAMap::gWAIUnivAttrMapLength = NS_ARRAY_LENGTH(nsARIAMap::gWAIUnivAttrMap);
+PRUint32
+nsARIAMap::gWAIUnivAttrMapLength = NS_ARRAY_LENGTH(nsARIAMap::gWAIUnivAttrMap);
nsRoleMapEntry*
aria::GetRoleMap(nsINode* aNode)
{
nsIContent* content = nsCoreUtils::GetRoleContent(aNode);
nsAutoString roles;
if (!content ||
!content->GetAttr(kNameSpaceID_None, nsGkAtoms::role, roles) ||
@@ -667,8 +668,19 @@ aria::GetRoleMap(nsINode* aNode)
low = idx + 1;
}
}
// Always use some entry if there is a non-empty role string
// To ensure an accessible object is created
return &sLandmarkRoleMap;
}
+
+PRUint64
+aria::UniversalStatesFor(mozilla::dom::Element* aElement)
+{
+ PRUint64 state = 0;
+ PRUint32 index = 0;
+ while (MapToState(sWAIUnivStateMap[index], aElement, &state))
+ index++;
+
+ return state;
+}
--- a/accessible/src/base/nsARIAMap.h
+++ b/accessible/src/base/nsARIAMap.h
@@ -195,54 +195,39 @@ struct nsARIAMap
/**
* Empty role map entry. Used by accessibility service to create an accessible
* if the accessible can't use role of used accessible class. For example,
* it is used for table cells that aren't contained by table.
*/
static nsRoleMapEntry gEmptyRoleMap;
/**
- * State map of ARIA states applied to any accessible not depending on
- * the role.
- */
- static mozilla::a11y::aria::EStateRule gWAIUnivStateMap[];
-
- /**
* Map of attribute to attribute characteristics.
*/
static nsAttributeCharacteristics gWAIUnivAttrMap[];
static PRUint32 gWAIUnivAttrMapLength;
-
- /**
- * Return accessible state from ARIA universal states applied to the given
- * element.
- */
- static PRUint64 UniversalStatesFor(mozilla::dom::Element* aElement)
- {
- PRUint64 state = 0;
- PRUint32 index = 0;
- while (mozilla::a11y::aria::MapToState(gWAIUnivStateMap[index],
- aElement, &state))
- index++;
-
- return state;
- }
};
namespace mozilla {
namespace a11y {
namespace aria {
/**
* Get the role map entry for a given DOM node. This will use the first
* ARIA role if the role attribute provides a space delimited list of roles.
*
* @param aNode [in] the DOM node to get the role map entry for
* @return a pointer to the role map entry for the ARIA role, or nsnull
* if none
*/
nsRoleMapEntry* GetRoleMap(nsINode* aNode);
+/**
+ * Return accessible state from ARIA universal states applied to the given
+ * element.
+ */
+PRUint64 UniversalStatesFor(mozilla::dom::Element* aElement);
+
} // namespace aria
} // namespace a11y
} // namespace mozilla
#endif
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -69,22 +69,16 @@ void nsAccessNode::LastRelease()
}
// ... then die.
delete this;
}
////////////////////////////////////////////////////////////////////////////////
// nsAccessNode public
-bool
-nsAccessNode::Init()
-{
- return true;
-}
-
void
nsAccessNode::Shutdown()
{
mContent = nsnull;
mDoc = nsnull;
}
--- a/accessible/src/base/nsAccessNode.h
+++ b/accessible/src/base/nsAccessNode.h
@@ -59,21 +59,16 @@ public:
DocAccessible* Document() const { return mDoc; }
/**
* Return the root document accessible for this accessnode.
*/
mozilla::a11y::RootAccessible* RootAccessible() const;
/**
- * Initialize the access node object, add it to the cache.
- */
- virtual bool Init();
-
- /**
* Shutdown the access node object.
*/
virtual void Shutdown();
/**
* Return frame for the given access node object.
*/
virtual nsIFrame* GetFrame() const;
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -189,16 +189,22 @@ Accessible::~Accessible()
}
void
Accessible::SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry)
{
mRoleMapEntry = aRoleMapEntry;
}
+bool
+Accessible::Init()
+{
+ return true;
+}
+
NS_IMETHODIMP
Accessible::GetDocument(nsIAccessibleDocument** aDocument)
{
NS_ENSURE_ARG_POINTER(aDocument);
NS_IF_ADDREF(*aDocument = Document());
return NS_OK;
}
@@ -1522,17 +1528,17 @@ void
Accessible::ApplyARIAState(PRUint64* aState) const
{
if (!mContent->IsElement())
return;
dom::Element* element = mContent->AsElement();
// Test for universal states first
- *aState |= nsARIAMap::UniversalStatesFor(element);
+ *aState |= aria::UniversalStatesFor(element);
if (mRoleMapEntry) {
// We only force the readonly bit off if we have a real mapping for the aria
// role. This preserves the ability for screen readers to use readonly
// (primarily on the document) as the hint for creating a virtual buffer.
if (mRoleMapEntry->role != roles::NOTHING)
*aState &= ~states::READONLY;
--- a/accessible/src/generic/Accessible.h
+++ b/accessible/src/generic/Accessible.h
@@ -122,16 +122,21 @@ public:
// nsAccessNode
virtual void Shutdown();
//////////////////////////////////////////////////////////////////////////////
// Public methods
/**
+ * Initialize the accessible.
+ */
+ virtual bool Init();
+
+ /**
* Get the description of this accessible.
*/
virtual void Description(nsString& aDescription);
/**
* Get the value of this accessible.
*/
virtual void Value(nsString& aValue);
--- a/accessible/src/jsat/AccessFu.jsm
+++ b/accessible/src/jsat/AccessFu.jsm
@@ -360,16 +360,31 @@ var AccessFu = {
}
case Ci.nsIAccessibleEvent.EVENT_FOCUS:
{
let acc = aEvent.accessible;
let doc = aEvent.accessibleDocument;
if (acc.role != Ci.nsIAccessibleRole.ROLE_DOCUMENT &&
doc.role != Ci.nsIAccessibleRole.ROLE_CHROME_WINDOW)
VirtualCursorController.moveCursorToObject(acc);
+
+ let [,extState] = Utils.getStates(acc);
+ let editableState = extState &
+ (Ci.nsIAccessibleStates.EXT_STATE_EDITABLE |
+ Ci.nsIAccessibleStates.EXT_STATE_MULTI_LINE);
+
+ if (editableState != VirtualCursorController.editableState) {
+ if (!VirtualCursorController.editableState)
+ this.presenters.forEach(
+ function(p) {
+ p.editingModeChanged(true);
+ }
+ );
+ }
+ VirtualCursorController.editableState = editableState;
break;
}
default:
break;
}
},
/**
--- a/accessible/src/jsat/Presenters.jsm
+++ b/accessible/src/jsat/Presenters.jsm
@@ -86,17 +86,22 @@ Presenter.prototype = {
* virtual cursor position.
*/
tabSelected: function tabSelected(aDocContext, aVCContext) {},
/**
* The viewport has changed, either a scroll, pan, zoom, or
* landscape/portrait toggle.
*/
- viewportChanged: function viewportChanged() {}
+ viewportChanged: function viewportChanged() {},
+
+ /**
+ * We have entered or left text editing mode.
+ */
+ editingModeChanged: function editingModeChanged(aIsEditing) {}
};
/**
* Visual presenter. Draws a box around the virtual cursor's position.
*/
function VisualPresenter() {}
@@ -298,32 +303,18 @@ AndroidPresenter.prototype = {
tabSelected: function AndroidPresenter_tabSelected(aDocContext, aVCContext) {
// Send a pivot change message with the full context utterance for this doc.
this.pivotChanged(aVCContext, Ci.nsIAccessiblePivot.REASON_NONE);
},
tabStateChanged: function AndroidPresenter_tabStateChanged(aDocObj,
aPageState) {
- let stateUtterance = UtteranceGenerator.
- genForTabStateChange(aDocObj, aPageState);
-
- if (!stateUtterance.length)
- return;
-
- this.sendMessageToJava({
- gecko: {
- type: 'Accessibility:Event',
- eventType: this.ANDROID_VIEW_TEXT_CHANGED,
- text: stateUtterance,
- addedCount: stateUtterance.join(' ').length,
- removedCount: 0,
- fromIndex: 0
- }
- });
+ this._appAnnounce(
+ UtteranceGenerator.genForTabStateChange(aDocObj, aPageState));
},
textChanged: function AndroidPresenter_textChanged(aIsInserted, aStart,
aLength, aText,
aModifiedText) {
let androidEvent = {
type: 'Accessibility:Event',
eventType: this.ANDROID_VIEW_TEXT_CHANGED,
@@ -359,16 +350,36 @@ AndroidPresenter.prototype = {
scrollX: win.scrollX,
scrollY: win.scrollY,
maxScrollX: win.scrollMaxX,
maxScrollY: win.scrollMaxY
}
});
},
+ editingModeChanged: function AndroidPresenter_editingModeChanged(aIsEditing) {
+ this._appAnnounce(UtteranceGenerator.genForEditingMode(aIsEditing));
+ },
+
+ _appAnnounce: function _appAnnounce(aUtterance) {
+ if (!aUtterance.length)
+ return;
+
+ this.sendMessageToJava({
+ gecko: {
+ type: 'Accessibility:Event',
+ eventType: this.ANDROID_VIEW_TEXT_CHANGED,
+ text: aUtterance,
+ addedCount: aUtterance.join(' ').length,
+ removedCount: 0,
+ fromIndex: 0
+ }
+ });
+ },
+
sendMessageToJava: function AndroidPresenter_sendMessageTojava(aMessage) {
return Cc['@mozilla.org/android/bridge;1'].
getService(Ci.nsIAndroidBridge).
handleGeckoMessage(JSON.stringify(aMessage));
}
};
/**
--- a/accessible/src/jsat/Utils.jsm
+++ b/accessible/src/jsat/Utils.jsm
@@ -54,16 +54,26 @@ var Utils = {
getViewport: function getViewport(aWindow) {
switch (this.OS) {
case 'Android':
return aWindow.BrowserApp.selectedTab.getViewport();
default:
return null;
}
+ },
+
+ getStates: function getStates(aAccessible) {
+ if (!aAccessible)
+ return [0, 0];
+
+ let state = {};
+ let extState = {};
+ aAccessible.getState(state, extState);
+ return [state.value, extState.value];
}
};
var Logger = {
DEBUG: 0,
INFO: 1,
WARNING: 2,
ERROR: 3,
--- a/accessible/src/jsat/UtteranceGenerator.jsm
+++ b/accessible/src/jsat/UtteranceGenerator.jsm
@@ -118,16 +118,26 @@ var UtteranceGenerator = {
return [gStringBundle.GetStringFromName('tabLoadStopped')];
case 'reload':
return [gStringBundle.GetStringFromName('tabReload')];
default:
return [];
}
},
+ /**
+ * Generates an utterance for announcing entering and leaving editing mode.
+ * @param {aIsEditing} boolean true if we are in editing mode
+ * @return {Array} The mode utterance
+ */
+ genForEditingMode: function genForEditingMode(aIsEditing) {
+ return [gStringBundle.GetStringFromName(
+ aIsEditing ? 'editingMode' : 'navigationMode')];
+ },
+
verbosityRoleMap: {
'menubar': INCLUDE_DESC,
'scrollbar': INCLUDE_DESC,
'grip': INCLUDE_DESC,
'alert': INCLUDE_DESC | INCLUDE_NAME,
'menupopup': INCLUDE_DESC,
'menuitem': INCLUDE_DESC,
'tooltip': INCLUDE_DESC,
--- a/accessible/src/jsat/VirtualCursorController.jsm
+++ b/accessible/src/jsat/VirtualCursorController.jsm
@@ -399,21 +399,18 @@ var TraversalRules = {
return Ci.nsIAccessibleTraversalRule.FILTER_MATCH;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAccessibleTraversalRule])
}
};
var VirtualCursorController = {
- NOT_EDITABLE: 0,
- SINGLE_LINE_EDITABLE: 1,
- MULTI_LINE_EDITABLE: 2,
-
exploreByTouch: false,
+ editableState: 0,
attach: function attach(aWindow) {
this.chromeWin = aWindow;
this.chromeWin.document.addEventListener('keypress', this, true);
this.chromeWin.document.addEventListener('mousemove', this, true);
},
detach: function detach() {
@@ -458,103 +455,107 @@ var VirtualCursorController = {
let document = Utils.getCurrentContentDoc(this.chromeWin);
let target = aEvent.target;
switch (aEvent.keyCode) {
case 0:
// an alphanumeric key was pressed, handle it separately.
// If it was pressed with either alt or ctrl, just pass through.
// If it was pressed with meta, pass the key on without the meta.
- if (this._isEditableText(target) ||
+ if (this.editableState ||
aEvent.ctrlKey || aEvent.altKey || aEvent.metaKey)
return;
let key = String.fromCharCode(aEvent.charCode);
let methodName = '', rule = {};
try {
[methodName, rule] = this.keyMap[key];
} catch (x) {
return;
}
this[methodName](document, false, rule);
break;
case aEvent.DOM_VK_END:
+ if (this.editableState) {
+ if (target.selectionEnd != target.textLength)
+ // Don't move forward if caret is not at end of entry.
+ // XXX: Fix for rtl
+ return;
+ else
+ target.blur();
+ }
this.moveForward(document, true);
break;
case aEvent.DOM_VK_HOME:
+ if (this.editableState) {
+ if (target.selectionEnd != 0)
+ // Don't move backward if caret is not at start of entry.
+ // XXX: Fix for rtl
+ return;
+ else
+ target.blur();
+ }
this.moveBackward(document, true);
break;
case aEvent.DOM_VK_RIGHT:
- if (this._isEditableText(target)) {
+ if (this.editableState) {
if (target.selectionEnd != target.textLength)
// Don't move forward if caret is not at end of entry.
// XXX: Fix for rtl
return;
else
target.blur();
}
this.moveForward(document, aEvent.shiftKey);
break;
case aEvent.DOM_VK_LEFT:
- if (this._isEditableText(target)) {
+ if (this.editableState) {
if (target.selectionEnd != 0)
// Don't move backward if caret is not at start of entry.
// XXX: Fix for rtl
return;
else
target.blur();
}
this.moveBackward(document, aEvent.shiftKey);
break;
case aEvent.DOM_VK_UP:
- if (this._isEditableText(target) == this.MULTI_LINE_EDITABLE) {
+ if (this.editableState & Ci.nsIAccessibleStates.EXT_STATE_MULTI_LINE) {
if (target.selectionEnd != 0)
// Don't blur content if caret is not at start of text area.
return;
else
target.blur();
}
if (Utils.OS == 'Android')
// Return focus to native Android browser chrome.
Cc['@mozilla.org/android/bridge;1'].
getService(Ci.nsIAndroidBridge).handleGeckoMessage(
JSON.stringify({ gecko: { type: 'ToggleChrome:Focus' } }));
break;
case aEvent.DOM_VK_RETURN:
case aEvent.DOM_VK_ENTER:
- if (this._isEditableText(target))
+ if (this.editableState)
return;
this.activateCurrent(document);
break;
default:
return;
}
aEvent.preventDefault();
aEvent.stopPropagation();
},
moveToPoint: function moveToPoint(aDocument, aX, aY) {
this.getVirtualCursor(aDocument).moveToPoint(TraversalRules.Simple,
aX, aY, true);
},
- _isEditableText: function _isEditableText(aElement) {
- // XXX: Support contentEditable and design mode
- if (aElement instanceof Ci.nsIDOMHTMLInputElement &&
- aElement.mozIsTextField(false))
- return this.SINGLE_LINE_EDITABLE;
-
- if (aElement instanceof Ci.nsIDOMHTMLTextAreaElement)
- return this.MULTI_LINE_EDITABLE;
-
- return this.NOT_EDITABLE;
- },
-
moveForward: function moveForward(aDocument, aLast, aRule) {
let virtualCursor = this.getVirtualCursor(aDocument);
if (aLast) {
virtualCursor.moveLast(TraversalRules.Simple);
} else {
try {
virtualCursor.moveNext(aRule || TraversalRules.Simple);
} catch (x) {
--- a/accessible/src/msaa/nsAccessNodeWrap.cpp
+++ b/accessible/src/msaa/nsAccessNodeWrap.cpp
@@ -388,17 +388,16 @@ nsAccessNodeWrap::MakeAccessNode(nsINode
NS_NOTREACHED("The node is a document which is not accessible!");
return NULL;
}
newNode = new nsAccessNodeWrap(content, mDoc);
if (!newNode)
return NULL;
- newNode->Init();
iNode = static_cast<ISimpleDOMNode*>(newNode);
iNode->AddRef();
}
return iNode;
}
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -14,16 +14,17 @@ builtin(include, build/autoconf/mozcommo
builtin(include, build/autoconf/acwinpaths.m4)dnl
builtin(include, build/autoconf/lto.m4)dnl
builtin(include, build/autoconf/gcc-pr49911.m4)dnl
builtin(include, build/autoconf/frameptr.m4)dnl
builtin(include, build/autoconf/compiler-opts.m4)dnl
builtin(include, build/autoconf/expandlibs.m4)dnl
builtin(include, build/autoconf/arch.m4)dnl
builtin(include, build/autoconf/android.m4)dnl
+builtin(include, build/autoconf/zlib.m4)dnl
MOZ_PROG_CHECKMSYS()
# Read the user's .mozconfig script. We can't do this in
# configure.in: autoconf puts the argument parsing code above anything
# expanded from configure.in, and we need to get the configure options
# from .mozconfig in place before that argument parsing code.
MOZ_READ_MOZCONFIG(.)
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -379,19 +379,16 @@ pref("dom.sms.enabled", true);
pref("dom.mozContacts.enabled", true);
// WebAlarms
pref("dom.mozAlarms.enabled", true);
// WebSettings
pref("dom.mozSettings.enabled", true);
-// Ignore X-Frame-Options headers.
-pref("b2g.ignoreXFrameOptions", true);
-
// controls if we want camera support
pref("device.camera.enabled", true);
pref("media.realtime_decoder.enabled", true);
// "Preview" landing of bug 710563, which is bogged down in analysis
// of talos regression. This is a needed change for higher-framerate
// CSS animations, and incidentally works around an apparent bug in
// our handling of requestAnimationFrame() listeners, which are
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -38,16 +38,19 @@
@BINPATH@/dictionaries/*
@BINPATH@/hyphenation/*
#ifdef XP_WIN32
@BINPATH@/uninstall/helper.exe
#endif
[xpcom]
@BINPATH@/dependentlibs.list
+#ifdef XP_WIN32
+@BINPATH@/@DLL_PREFIX@gkmedias@DLL_SUFFIX@
+#endif
#ifndef MOZ_STATIC_JS
@BINPATH@/@DLL_PREFIX@mozjs@DLL_SUFFIX@
#endif
@BINPATH@/@DLL_PREFIX@plc4@DLL_SUFFIX@
@BINPATH@/@DLL_PREFIX@plds4@DLL_SUFFIX@
@BINPATH@/@DLL_PREFIX@xpcom@DLL_SUFFIX@
@BINPATH@/@DLL_PREFIX@nspr4@DLL_SUFFIX@
@BINPATH@/@DLL_PREFIX@mozalloc@DLL_SUFFIX@
@@ -468,16 +471,19 @@
@BINPATH@/components/Webapps.manifest
@BINPATH@/components/AppsService.js
@BINPATH@/components/AppsService.manifest
@BINPATH@/components/SystemMessageInternal.js
@BINPATH@/components/SystemMessageManager.js
@BINPATH@/components/SystemMessageManager.manifest
+@BINPATH@/components/AppProtocolHandler.js
+@BINPATH@/components/AppProtocolHandler.manifest
+
; Modules
@BINPATH@/modules/*
; Safe Browsing
@BINPATH@/components/nsURLClassifier.manifest
@BINPATH@/components/nsUrlClassifierHashCompleter.js
@BINPATH@/components/nsUrlClassifierListManager.js
@BINPATH@/components/nsUrlClassifierLib.js
--- a/browser/app/macbuild/Contents/_CodeSignature/CodeResources
+++ b/browser/app/macbuild/Contents/_CodeSignature/CodeResources
@@ -7,16 +7,22 @@
<key>^Info.plist$</key>
<true/>
<key>^PkgInfo$</key>
<true/>
<key>^MacOS/</key>
<true/>
<key>^Resources/</key>
<true/>
+ <key>^MacOS/distribution/.*</key><dict>
+ <key>omit</key>
+ <true/>
+ <key>weight</key>
+ <real>10</real>
+ </dict>
<key>^MacOS/updates/.*</key><dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^MacOS/active-update.xml$</key><dict>
<key>omit</key>
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -235,50 +235,23 @@ int main(int argc, char* argv[])
strcpy(++lastSlash, XPCOM_DLL);
int gotCounters;
#if defined(XP_UNIX)
struct rusage initialRUsage;
gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage);
#elif defined(XP_WIN)
- // Don't change the order of these enumeration constants, the order matters
- // for reporting telemetry data. If new values are added adjust the
- // STARTUP_USING_PRELOAD_TRIAL histogram.
- enum PreloadType{ PREFETCH_PRELOAD,
- PREFETCH_NO_PRELOAD,
- NO_PREFETCH_PRELOAD,
- NO_PREFETCH_NO_PRELOAD };
- PreloadType preloadType;
-
IO_COUNTERS ioCounters;
gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
-
- srand(time(NULL));
- bool shouldUsePreload = rand() % 2 == 0;
+#endif
- if (IsPrefetchDisabledViaService()) {
- if (shouldUsePreload) {
- preloadType = NO_PREFETCH_PRELOAD;
- } else {
- preloadType = NO_PREFETCH_NO_PRELOAD;
- }
- } else {
- if (shouldUsePreload) {
- preloadType = PREFETCH_PRELOAD;
- } else {
- preloadType = PREFETCH_NO_PRELOAD;
- }
- }
-
- if (shouldUsePreload)
+#if !defined(XP_WIN)
+ XPCOMGlueEnablePreload();
#endif
- {
- XPCOMGlueEnablePreload();
- }
rv = XPCOMGlueStartup(exePath);
if (NS_FAILED(rv)) {
Output("Couldn't load XPCOM.\n");
return 255;
}
// Reset exePath so that it is the directory name and not the xpcom dll name
*lastSlash = 0;
@@ -290,21 +263,16 @@ int main(int argc, char* argv[])
}
XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
#ifdef XRE_HAS_DLL_BLOCKLIST
XRE_SetupDllBlocklist();
#endif
-#if defined(XP_WIN)
- XRE_TelemetryAccumulate(mozilla::Telemetry::STARTUP_USING_PRELOAD_TRIAL,
- preloadType);
-#endif
-
if (gotCounters) {
#if defined(XP_WIN)
XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_OPS,
int(ioCounters.ReadOperationCount));
XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_TRANSFER,
int(ioCounters.ReadTransferCount / 1024));
IO_COUNTERS newIoCounters;
if (GetProcessIoCounters(GetCurrentProcess(), &newIoCounters)) {
--- a/browser/base/content/abouthome/aboutHome.css
+++ b/browser/base/content/abouthome/aboutHome.css
@@ -92,18 +92,18 @@ body[dir=rtl] #searchText {
padding: 0 9px;
border: 1px solid;
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
-moz-border-start: 1px solid transparent;
border-radius: 0 2.5px 2.5px 0;
box-shadow: 0 0 2px hsla(0,0%,100%,.5) inset,
0 1px 0 hsla(0,0%,100%,.2);
cursor: pointer;
- -moz-transition-property: background-color, border-color, box-shadow;
- -moz-transition-duration: 150ms;
+ transition-property: background-color, border-color, box-shadow;
+ transition-duration: 150ms;
}
body[dir=rtl] #searchSubmit {
border-radius: 2.5px 0 0 2.5px;
}
#searchText:focus + #searchSubmit,
#searchText + #searchSubmit:hover {
@@ -124,17 +124,17 @@ body[dir=rtl] #searchSubmit {
0 0 0 1px hsla(0,0%,100%,.1) inset,
0 1px 0 hsla(210,54%,20%,.03),
0 0 4px hsla(206,100%,20%,.2);
}
#searchText + #searchSubmit:hover:active {
box-shadow: 0 1px 1px hsla(211,79%,6%,.1) inset,
0 0 1px hsla(211,79%,6%,.2) inset;
- -moz-transition-duration: 0ms;
+ transition-duration: 0ms;
}
#defaultSnippet1,
#defaultSnippet2 {
display: block;
min-height: 38px;
background: 30px center no-repeat;
padding: 6px 0;
@@ -191,35 +191,35 @@ body[narrow] #launcher[session] {
vertical-align: top;
white-space: normal;
background: transparent padding-box;
border: 1px solid transparent;
border-radius: 2.5px;
color: #525c66;
font-size: 75%;
cursor: pointer;
- -moz-transition-property: background-color, border-color, box-shadow;
- -moz-transition-duration: 150ms;
+ transition-property: background-color, border-color, box-shadow;
+ transition-duration: 150ms;
}
body[narrow] #launcher[session] > .launchButton {
margin: 4px 1px;
}
.launchButton:hover {
background-color: hsla(211,79%,6%,.03);
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
}
.launchButton:hover:active {
background-image: -moz-linear-gradient(hsla(211,79%,6%,.02), hsla(211,79%,6%,.05));
border-color: hsla(210,54%,20%,.2) hsla(210,54%,20%,.23) hsla(210,54%,20%,.25);
box-shadow: 0 1px 1px hsla(211,79%,6%,.05) inset,
0 0 1px hsla(211,79%,6%,.1) inset;
- -moz-transition-duration: 0ms;
+ transition-duration: 0ms;
}
.launchButton[hidden],
#launcher:not([session]) > #restorePreviousSessionSeparator,
#launcher:not([session]) > #restorePreviousSession {
display: none;
}
@@ -309,17 +309,17 @@ body[narrow] #restorePreviousSession::be
width: 32px;
}
#aboutMozilla {
display: block;
position: relative; /* pin wordmark to edge of document, not of viewport */
-moz-box-ordinal-group: 0;
opacity: .5;
- -moz-transition: opacity 150ms;
+ transition: opacity 150ms;
}
#aboutMozilla:hover {
opacity: 1;
}
#aboutMozilla::before {
content: url("chrome://browser/content/abouthome/mozilla.png");
--- a/browser/base/content/browser-fullScreen.js
+++ b/browser/base/content/browser-fullScreen.js
@@ -22,18 +22,23 @@ var FullScreen = {
document.getElementById("exitFullScreenItem").hidden = !enterFS;
#endif
// On OS X Lion we don't want to hide toolbars when entering fullscreen, unless
// we're entering DOM fullscreen, in which case we should hide the toolbars.
// If we're leaving fullscreen, then we'll go through the exit code below to
// make sure toolbars are made visible in the case of DOM fullscreen.
if (enterFS && this.useLionFullScreen) {
- if (document.mozFullScreen)
+ if (document.mozFullScreen) {
this.showXULChrome("toolbar", false);
+ }
+ else {
+ gNavToolbox.setAttribute("inFullscreen", true);
+ document.documentElement.setAttribute("inFullscreen", true);
+ }
return;
}
// show/hide menubars, toolbars (except the full screen toolbar)
this.showXULChrome("toolbar", !enterFS);
if (enterFS) {
// Add a tiny toolbar to receive mouseover and dragenter events, and provide affordance.
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -514,16 +514,17 @@
label="&webDeveloperMenu.label;"
accesskey="&webDeveloperMenu.accesskey;">
<menupopup id="menuWebDeveloperPopup">
<menuitem id="menu_devToolbar"
type="checkbox"
autocheck="false"
hidden="true"
label="&devToolbarMenu.label;"
+ accesskey="&devToolbarMenu.accesskey;"
key="key_devToolbar"
command="Tools:DevToolbar"/>
<menuitem id="webConsole"
type="checkbox"
label="&webConsoleCmd.label;"
accesskey="&webConsoleCmd.accesskey;"
key="key_webConsole"
command="Tools:WebConsole"/>
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -84,16 +84,17 @@
<command id="cmd_fullZoomEnlarge" oncommand="FullZoom.enlarge()"/>
<command id="cmd_fullZoomReset" oncommand="FullZoom.reset()"/>
<command id="cmd_fullZoomToggle" oncommand="ZoomManager.toggleZoom();"/>
<command id="Browser:OpenLocation" oncommand="openLocation();"/>
<command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
<command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
<command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true"/>
+ <command id="Tools:DevToolbarFocus" oncommand="DeveloperToolbar.focus();" disabled="true"/>
<command id="Tools:WebConsole" oncommand="HUDConsoleUI.toggleHUD();"/>
<command id="Tools:Inspect" oncommand="InspectorUI.toggleInspectorUI();" disabled="true"/>
<command id="Tools:Debugger" oncommand="DebuggerUI.toggleDebugger();" disabled="true"/>
<command id="Tools:RemoteDebugger" oncommand="DebuggerUI.toggleRemoteDebugger();" disabled="true"/>
<command id="Tools:ChromeDebugger" oncommand="DebuggerUI.toggleChromeDebugger();" disabled="true"/>
<command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true"/>
<command id="Tools:StyleEditor" oncommand="StyleEditor.toggle();" disabled="true"/>
<command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true"/>
@@ -220,16 +221,18 @@
#ifdef XP_GNOME
<key id="key_search2" key="&searchFocusUnix.commandkey;" command="Tools:Search" modifiers="accel"/>
<key id="key_openDownloads" key="&downloadsUnix.commandkey;" command="Tools:Downloads" modifiers="accel,shift"/>
#else
<key id="key_openDownloads" key="&downloads.commandkey;" command="Tools:Downloads" modifiers="accel"/>
#endif
<key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/>
<key id="key_errorConsole" key="&errorConsoleCmd.commandkey;" oncommand="toJavaScriptConsole();" modifiers="accel,shift" disabled="true"/>
+ <key id="key_devToolbar" keycode="&devToolbar.keycode;" modifiers="shift"
+ keytext="&devToolbar.keytext;" command="Tools:DevToolbarFocus"/>
<key id="key_webConsole" key="&webConsoleCmd.commandkey;" oncommand="HUDConsoleUI.toggleHUD();"
#ifdef XP_MACOSX
modifiers="accel,alt"
#else
modifiers="accel,shift"
#endif
/>
<key id="key_debugger" key="&debuggerMenu.commandkey;" command="Tools:Debugger"
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -33,28 +33,28 @@ tabbrowser {
-moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tab");
}
.tabbrowser-tab:not([pinned]) {
-moz-box-flex: 100;
max-width: 250px;
min-width: 100px;
width: 0;
- -moz-transition: min-width 200ms ease-out,
- max-width 250ms ease-out,
- opacity 50ms ease-out 20ms /* hide the tab for the first 20ms of the max-width transition */;
+ transition: min-width 200ms ease-out,
+ max-width 250ms ease-out,
+ opacity 50ms ease-out 20ms /* hide the tab for the first 20ms of the max-width transition */;
}
.tabbrowser-tab:not([pinned]):not([fadein]) {
max-width: 0.1px;
min-width: 0.1px;
opacity: 0 !important;
- -moz-transition: min-width 200ms ease-out,
- max-width 250ms ease-out,
- opacity 50ms ease-out 180ms /* hide the tab for the last 20ms of the max-width transition */;
+ transition: min-width 200ms ease-out,
+ max-width 250ms ease-out,
+ opacity 50ms ease-out 180ms /* hide the tab for the last 20ms of the max-width transition */;
}
.tab-throbber:not([fadein]):not([pinned]),
.tab-label:not([fadein]):not([pinned]),
.tab-icon-image:not([fadein]):not([pinned]),
.tab-close-button:not([fadein]):not([pinned]) {
display: none;
}
@@ -372,18 +372,18 @@ window[chromehidden~="toolbar"] toolbar:
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#full-screen-warning-container[fade-warning-out] {
- -moz-transition-property: opacity !important;
- -moz-transition-duration: 500ms !important;
+ transition-property: opacity !important;
+ transition-duration: 500ms !important;
opacity: 0.0;
}
#full-screen-warning-message {
pointer-events: auto;
/* We must specify a max-width, otherwise word-wrap:break-word doesn't
work in descendant <description> and <label> elements. Bug 630864. */
max-width: 800px;
@@ -513,27 +513,27 @@ statuspanel[type=status] {
@media all and (max-width: 800px) {
statuspanel[type=status] {
min-width: 33%;
}
}
statuspanel[type=overLink] {
- -moz-transition: opacity 120ms ease-out;
+ transition: opacity 120ms ease-out;
direction: ltr;
}
statuspanel[inactive] {
- -moz-transition: none;
+ transition: none;
opacity: 0;
}
statuspanel[inactive][previoustype=overLink] {
- -moz-transition: opacity 200ms ease-out;
+ transition: opacity 200ms ease-out;
}
.statuspanel-inner {
height: 3em;
width: 100%;
-moz-box-align: end;
}
@@ -584,19 +584,19 @@ vbox[anonid=browserContainer][responsive
overflow: auto;
}
.devtools-responsiveui-toolbar:-moz-locale-dir(rtl) {
-moz-box-pack: end;
}
stack[anonid=browserStack][responsivemode] {
- -moz-transition-duration: 200ms;
- -moz-transition-timing-function: linear;
+ transition-duration: 200ms;
+ transition-timing-function: linear;
}
stack[anonid=browserStack][responsivemode] {
- -moz-transition-property: min-width, max-width, min-height, max-height;
+ transition-property: min-width, max-width, min-height, max-height;
}
stack[anonid=browserStack][responsivemode][notransition] {
- -moz-transition: none;
+ transition: none;
}
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1389,16 +1389,17 @@ var gBrowserInit = {
setUrlAndSearchBarWidthForConditionalForwardButton();
});
// Enable developer toolbar?
let devToolbarEnabled = gPrefService.getBoolPref("devtools.toolbar.enabled");
if (devToolbarEnabled) {
document.getElementById("menu_devToolbar").hidden = false;
document.getElementById("Tools:DevToolbar").removeAttribute("disabled");
+ document.getElementById("Tools:DevToolbarFocus").removeAttribute("disabled");
#ifdef MENUBAR_CAN_AUTOHIDE
document.getElementById("appmenu_devToolbar").hidden = false;
#endif
// Show the toolbar if it was previously visible
if (gPrefService.getBoolPref("devtools.toolbar.visible")) {
DeveloperToolbar.show(false);
}
@@ -6052,27 +6053,56 @@ function WindowIsClosing()
/**
* Checks if this is the last full *browser* window around. If it is, this will
* be communicated like quitting. Otherwise, we warn about closing multiple tabs.
* @returns true if closing can proceed, false if it got cancelled.
*/
function warnAboutClosingWindow() {
// Popups aren't considered full browser windows.
- if (!toolbar.visible)
+ let isPBWindow = gPrivateBrowsingUI.privateWindow;
+ if (!isPBWindow && !toolbar.visible)
return gBrowser.warnAboutClosingTabs(true);
// Figure out if there's at least one other browser window around.
let e = Services.wm.getEnumerator("navigator:browser");
+ let otherPBWindowExists = false;
+ let warnAboutClosingTabs = false;
while (e.hasMoreElements()) {
let win = e.getNext();
- if (win != window && win.toolbar.visible)
- return gBrowser.warnAboutClosingTabs(true);
+ if (win != window) {
+ if (isPBWindow &&
+ ("gPrivateBrowsingUI" in win) &&
+ win.gPrivateBrowsingUI.privateWindow)
+ otherPBWindowExists = true;
+ if (win.toolbar.visible)
+ warnAboutClosingTabs = true;
+ // If the current window is not in private browsing mode we don't need to
+ // look for other pb windows, we can leave the loop when finding the
+ // first non-popup window. If however the current window is in private
+ // browsing mode then we need at least one other pb and one non-popup
+ // window to break out early.
+ if ((!isPBWindow || otherPBWindowExists) && warnAboutClosingTabs)
+ break;
+ }
}
+ if (isPBWindow && !otherPBWindowExists) {
+ let exitingCanceled = Cc["@mozilla.org/supports-PRBool;1"].
+ createInstance(Ci.nsISupportsPRBool);
+ exitingCanceled.data = false;
+ Services.obs.notifyObservers(exitingCanceled,
+ "last-pb-context-exiting",
+ null);
+ if (exitingCanceled.data)
+ return false;
+ }
+ if (warnAboutClosingTabs)
+ return gBrowser.warnAboutClosingTabs(true);
+
let os = Services.obs;
let closingCanceled = Cc["@mozilla.org/supports-PRBool;1"].
createInstance(Ci.nsISupportsPRBool);
os.notifyObservers(closingCanceled,
"browser-lastwindow-close-requested", null);
if (closingCanceled.data)
return false;
--- a/browser/base/content/highlighter.css
+++ b/browser/base/content/highlighter.css
@@ -20,19 +20,19 @@
#highlighter-veil-container:not([dim]) > hbox > .highlighter-veil {
visibility: hidden;
}
#highlighter-veil-container:not([disable-transitions]) > .highlighter-veil,
#highlighter-veil-container:not([disable-transitions]) > #highlighter-veil-middlebox,
#highlighter-veil-container:not([disable-transitions]) > #highlighter-veil-middlebox > .highlighter-veil,
#highlighter-veil-container:not([disable-transitions]) > #highlighter-veil-middlebox > #highlighter-veil-transparentbox {
- -moz-transition-property: width, height;
- -moz-transition-duration: 0.1s;
- -moz-transition-timing-function: linear;
+ transition-property: width, height;
+ transition-duration: 0.1s;
+ transition-timing-function: linear;
}
#highlighter-veil-bottombox,
#highlighter-veil-rightbox {
-moz-box-flex: 1;
}
#highlighter-veil-middlebox:-moz-locale-dir(rtl) {
@@ -48,19 +48,19 @@
*/
#highlighter-nodeinfobar-container {
position: absolute;
max-width: 95%;
}
#highlighter-nodeinfobar-container:not([disable-transitions]) {
- -moz-transition-property: top, left;
- -moz-transition-duration: 0.1s;
- -moz-transition-timing-function: linear;
+ transition-property: top, left;
+ transition-duration: 0.1s;
+ transition-timing-function: linear;
}
#highlighter-nodeinfobar-text {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
direction: ltr;
}
@@ -115,16 +115,16 @@ html|*#highlighter-nodeinfobar-tagname {
}
#inspector-layoutview-container > iframe {
/* header size */
height: 28px;
}
#inspector-layoutview-container:not([disable-transitions]) > iframe {
- -moz-transition-property: height;
- -moz-transition-duration: 0.2s;
+ transition-property: height;
+ transition-duration: 0.2s;
}
#inspector-layoutview-container > iframe[open] {
/* header size + layout view size: 28px + 145px */
height: 173px;
}
--- a/browser/base/content/newtab/newTab.css
+++ b/browser/base/content/newtab/newTab.css
@@ -63,18 +63,18 @@ input[type=button] {
/* GRID */
#newtab-grid {
display: -moz-box;
-moz-box-flex: 5;
-moz-box-orient: vertical;
min-width: 600px;
min-height: 400px;
- -moz-transition: 100ms ease-out;
- -moz-transition-property: opacity;
+ transition: 100ms ease-out;
+ transition-property: opacity;
}
#newtab-grid[page-disabled] {
opacity: 0;
}
#newtab-grid[locked],
#newtab-grid[page-disabled] {
@@ -94,43 +94,43 @@ input[type=button] {
display: -moz-box;
-moz-box-flex: 1;
}
/* SITES */
.newtab-site {
position: relative;
-moz-box-flex: 1;
- -moz-transition: 100ms ease-out;
- -moz-transition-property: top, left, opacity;
+ transition: 100ms ease-out;
+ transition-property: top, left, opacity;
}
.newtab-site[frozen] {
position: absolute;
pointer-events: none;
}
.newtab-site[dragged] {
- -moz-transition-property: none;
+ transition-property: none;
z-index: 10;
}
/* LINK + THUMBNAILS */
.newtab-link,
.newtab-thumbnail {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
.newtab-thumbnail {
opacity: .8;
- -moz-transition: opacity 100ms ease-out;
+ transition: opacity 100ms ease-out;
}
.newtab-thumbnail[dragged],
.newtab-link:-moz-focusring > .newtab-thumbnail,
.newtab-site:hover > .newtab-link > .newtab-thumbnail {
opacity: 1;
}
@@ -145,17 +145,17 @@ input[type=button] {
text-overflow: ellipsis;
}
/* CONTROLS */
.newtab-control {
position: absolute;
top: 4px;
opacity: 0;
- -moz-transition: opacity 100ms ease-out;
+ transition: opacity 100ms ease-out;
}
.newtab-control:-moz-focusring,
.newtab-site:hover > .newtab-control {
opacity: 1;
}
.newtab-control[dragged] {
--- a/browser/base/content/tabbrowser.css
+++ b/browser/base/content/tabbrowser.css
@@ -46,10 +46,10 @@ tabpanels {
display: none;
}
.closing-tabs-spacer {
pointer-events: none;
}
.tabbrowser-tabs:not(:hover) > .tabbrowser-arrowscrollbox > .closing-tabs-spacer {
- -moz-transition: width .15s ease-out;
+ transition: width .15s ease-out;
}
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -143,16 +143,17 @@ endif
browser_bug623155.js \
browser_bug623893.js \
browser_bug624734.js \
browser_bug647886.js \
browser_bug655584.js \
browser_bug664672.js \
browser_bug710878.js \
browser_bug719271.js \
+ browser_bug724239.js \
browser_bug735471.js \
browser_bug743421.js \
browser_bug749738.js \
browser_bug763468.js \
browser_bug767836.js \
browser_canonizeURL.js \
browser_customize.js \
browser_findbarClose.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug724239.js
@@ -0,0 +1,28 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+ waitForExplicitFinish();
+ BrowserOpenTab();
+
+ let tab = gBrowser.selectedTab;
+ let browser = tab.linkedBrowser;
+
+ registerCleanupFunction(function () { gBrowser.removeTab(tab); });
+
+ whenBrowserLoaded(browser, function () {
+ browser.loadURI("http://example.com/");
+
+ whenBrowserLoaded(browser, function () {
+ ok(!gBrowser.canGoBack, "about:newtab wasn't added to the session history");
+ finish();
+ });
+ });
+}
+
+function whenBrowserLoaded(aBrowser, aCallback) {
+ aBrowser.addEventListener("load", function onLoad() {
+ aBrowser.removeEventListener("load", onLoad, true);
+ executeSoon(aCallback);
+ }, true);
+}
--- a/browser/base/content/test/browser_sanitizeDialog.js
+++ b/browser/base/content/test/browser_sanitizeDialog.js
@@ -460,22 +460,16 @@ var gAllTests = [
var localStorage = dsm.getLocalStorageForPrincipal(principal, URL);
localStorage.setItem("test", "value");
// Store something to the offline cache
const nsICache = Components.interfaces.nsICache;
var cs = Components.classes["@mozilla.org/network/cache-service;1"]
.getService(Components.interfaces.nsICacheService);
var session = cs.createSession(URL + "/manifest", nsICache.STORE_OFFLINE, nsICache.STREAM_BASED);
- var cacheEntry = session.openCacheEntry(URL, nsICache.ACCESS_READ_WRITE, false);
- var stream = cacheEntry.openOutputStream(0);
- var content = "content";
- stream.write(content, content.length);
- stream.close();
- cacheEntry.close();
// Open the dialog
let wh = new WindowHelper();
wh.onload = function () {
this.selectDuration(Sanitizer.TIMESPAN_EVERYTHING);
// Show details
this.toggleDetails();
// Clear only offlineApps
@@ -501,17 +495,30 @@ var gAllTests = [
{
// Do not enumerate entries.
return false;
}
};
cs.visitEntries(visitor);
is(size, 0, "offline application cache entries evicted");
};
- wh.open();
+
+ var cacheListener = {
+ onCacheEntryAvailable: function (entry, access, status) {
+ is(status, Cr.NS_OK);
+ var stream = entry.openOutputStream(0);
+ var content = "content";
+ stream.write(content, content.length);
+ stream.close();
+ entry.close();
+ wh.open();
+ }
+ };
+
+ session.asyncOpenCacheEntry(URL, nsICache.ACCESS_READ_WRITE, cacheListener);
},
function () {
// Test for offline apps permission deletion
// Prepare stuff, we will work with www.example.com
var URL = "http://www.example.com";
var ios = Cc["@mozilla.org/network/io-service;1"]
--- a/browser/components/places/tests/unit/test_clearHistory_shutdown.js
+++ b/browser/components/places/tests/unit/test_clearHistory_shutdown.js
@@ -61,19 +61,17 @@ let notificationsObserver = {
do_check_false(stmt.executeStep());
stmt.reset();
});
} finally {
stmt.finalize();
}
// Check cache.
- do_check_false(cacheExists(URL));
-
- do_test_finished();
+ checkCache(URL);
}
}
let timeInMicroseconds = Date.now() * 1000;
function run_test() {
do_test_pending();
@@ -100,17 +98,20 @@ function run_test() {
print("Add visits.");
URIS.forEach(function(aUrl) {
PlacesUtils.history.addVisit(uri(aUrl), timeInMicroseconds++, null,
PlacesUtils.history.TRANSITION_TYPED,
false, 0);
});
print("Add cache.");
storeCache(URL, "testData");
+}
+function run_test_continue()
+{
print("Simulate and wait shutdown.");
getDistinctNotifications().forEach(
function (topic)
Services.obs.addObserver(notificationsObserver, topic, false)
);
shutdownPlaces();
@@ -123,43 +124,51 @@ function getDistinctNotifications() {
return [ar[i] for (i in ar) if (ar.slice(0, i).indexOf(ar[i]) == -1)];
}
function storeCache(aURL, aContent) {
let cache = Cc["@mozilla.org/network/cache-service;1"].
getService(Ci.nsICacheService);
let session = cache.createSession("FTP", Ci.nsICache.STORE_ANYWHERE,
Ci.nsICache.STREAM_BASED);
- let cacheEntry =
- session.openCacheEntry(aURL, Ci.nsICache.ACCESS_READ_WRITE, false);
- cacheEntry.setMetaDataElement("servertype", "0");
- var oStream = cacheEntry.openOutputStream(0);
+ var storeCacheListener = {
+ onCacheEntryAvailable: function (entry, access, status) {
+ do_check_eq(status, Cr.NS_OK);
+
+ entry.setMetaDataElement("servertype", "0");
+ var os = entry.openOutputStream(0);
- var written = oStream.write(aContent, aContent.length);
- if (written != aContent.length) {
- do_throw("oStream.write has not written all data!\n" +
- " Expected: " + written + "\n" +
- " Actual: " + aContent.length + "\n");
- }
- oStream.close();
- cacheEntry.close();
+ var written = os.write(aContent, aContent.length);
+ if (written != aContent.length) {
+ do_throw("os.write has not written all data!\n" +
+ " Expected: " + written + "\n" +
+ " Actual: " + aContent.length + "\n");
+ }
+ os.close();
+ entry.close();
+ do_execute_soon(run_test_continue);
+ }
+ };
+
+ session.asyncOpenCacheEntry(aURL,
+ Ci.nsICache.ACCESS_READ_WRITE,
+ storeCacheListener);
}
-function cacheExists(aURL) {
+
+function checkCache(aURL) {
let cache = Cc["@mozilla.org/network/cache-service;1"].
getService(Ci.nsICacheService);
let session = cache.createSession("FTP", Ci.nsICache.STORE_ANYWHERE,
Ci.nsICache.STREAM_BASED);
- try {
- let cacheEntry =
- session.openCacheEntry(aURL, Ci.nsICache.ACCESS_READ, true);
- } catch (e) {
- if (e.result == Cr.NS_ERROR_CACHE_KEY_NOT_FOUND ||
- e.result == Cr.NS_ERROR_FAILURE)
- return false;
-
- // Throw the textual error description.
- do_throw(e);
- }
- cacheEntry.close();
- return true;
+
+ var checkCacheListener = {
+ onCacheEntryAvailable: function (entry, access, status) {
+ do_check_eq(status, Cr.NS_ERROR_CACHE_KEY_NOT_FOUND);
+ do_test_finished();
+ }
+ };
+
+ session.asyncOpenCacheEntry(aURL,
+ Ci.nsICache.ACCESS_READ,
+ checkCacheListener);
}
--- a/browser/components/preferences/applications.js
+++ b/browser/components/preferences/applications.js
@@ -1080,23 +1080,21 @@ var gApplicationsPane = {
* the last one is the one that the application will use. That may not be
* correct, but it's how we've been doing it for years.
*
* Perhaps we should instead query navigator.mimeTypes for the set of types
* supported by the application and then get the plugin from each MIME type's
* enabledPlugin property. But if there's a plugin for a type, we need
* to know about it even if it isn't enabled, since we're going to give
* the user an option to enable it.
- *
- * I'll also note that my reading of nsPluginTag::RegisterWithCategoryManager
- * suggests that enabledPlugin is only determined during registration
- * and does not get updated when plugin.disable_full_page_plugin_for_types
- * changes (unless modification of that preference spawns reregistration).
- * So even if we could use enabledPlugin to get the plugin that would be used,
- * we'd still need to check the pref ourselves to find out if it's enabled.
+ *
+ * Also note that enabledPlugin does not get updated when
+ * plugin.disable_full_page_plugin_for_types changes, so even if we could use
+ * enabledPlugin to get the plugin that would be used, we'd still need to
+ * check the pref ourselves to find out if it's enabled.
*/
_loadPluginHandlers: function() {
for (let i = 0; i < navigator.plugins.length; ++i) {
let plugin = navigator.plugins[i];
for (let j = 0; j < plugin.length; ++j) {
let type = plugin[j].type;
let handlerInfoWrapper;
--- a/browser/components/preferences/in-content/applications.js
+++ b/browser/components/preferences/in-content/applications.js
@@ -1067,23 +1067,21 @@ var gApplicationsPane = {
* the last one is the one that the application will use. That may not be
* correct, but it's how we've been doing it for years.
*
* Perhaps we should instead query navigator.mimeTypes for the set of types
* supported by the application and then get the plugin from each MIME type's
* enabledPlugin property. But if there's a plugin for a type, we need
* to know about it even if it isn't enabled, since we're going to give
* the user an option to enable it.
- *
- * I'll also note that my reading of nsPluginTag::RegisterWithCategoryManager
- * suggests that enabledPlugin is only determined during registration
- * and does not get updated when plugin.disable_full_page_plugin_for_types
- * changes (unless modification of that preference spawns reregistration).
- * So even if we could use enabledPlugin to get the plugin that would be used,
- * we'd still need to check the pref ourselves to find out if it's enabled.
+ *
+ * Also note that enabledPlugin does not get updated when
+ * plugin.disable_full_page_plugin_for_types changes, so even if we could use
+ * enabledPlugin to get the plugin that would be used, we'd still need to
+ * check the pref ourselves to find out if it's enabled.
*/
_loadPluginHandlers: function() {
for (let i = 0; i < navigator.plugins.length; ++i) {
let plugin = navigator.plugins[i];
for (let j = 0; j < plugin.length; ++j) {
let type = plugin[j].type;
let handlerInfoWrapper;
--- a/browser/components/shell/src/nsWindowsShellService.cpp
+++ b/browser/components/shell/src/nsWindowsShellService.cpp
@@ -223,17 +223,21 @@ GetHelperPath(nsAutoString& aPath)
NS_ENSURE_SUCCESS(rv, rv);
rv = appHelper->AppendNative(NS_LITERAL_CSTRING("uninstall"));
NS_ENSURE_SUCCESS(rv, rv);
rv = appHelper->AppendNative(NS_LITERAL_CSTRING("helper.exe"));
NS_ENSURE_SUCCESS(rv, rv);
- return appHelper->GetPath(aPath);
+ rv = appHelper->GetPath(aPath);
+
+ aPath.Insert(L'"', 0);
+ aPath.Append(L'"');
+ return rv;
}
nsresult
LaunchHelper(nsAutoString& aPath)
{
STARTUPINFOW si = {sizeof(si), 0};
PROCESS_INFORMATION pi = {0};
--- a/browser/components/tabview/iq.js
+++ b/browser/components/tabview/iq.js
@@ -563,29 +563,29 @@ iQClass.prototype = {
let cStyle = window.getComputedStyle(elem, null);
for (let prop in css) {
prop = prop.replace(rupper, "-$1").toLowerCase();
iQ(elem).css(prop, cStyle.getPropertyValue(prop));
}
});
this.css({
- '-moz-transition-property': Object.keys(css).join(", "),
- '-moz-transition-duration': (duration / 1000) + 's',
- '-moz-transition-timing-function': easing
+ 'transition-property': Object.keys(css).join(", "),
+ 'transition-duration': (duration / 1000) + 's',
+ 'transition-timing-function': easing
});
this.css(css);
let self = this;
setTimeout(function() {
self.css({
- '-moz-transition-property': 'none',
- '-moz-transition-duration': '',
- '-moz-transition-timing-function': ''
+ 'transition-property': 'none',
+ 'transition-duration': '',
+ 'transition-timing-function': ''
});
if (typeof options.complete == "function")
options.complete.apply(self);
}, duration);
return this;
},
--- a/browser/components/tabview/test/browser_tabview_bug580412.js
+++ b/browser/components/tabview/test/browser_tabview_bug580412.js
@@ -22,17 +22,17 @@ function onTabViewShown() {
ok(!TabView.isVisible(), "TabView is hidden");
finish();
});
}
// we need to stop the setBounds() css animation or else the test will
// fail in single-mode because the group is newly created "ontabshown".
let $container = contentWindow.iQ(currentActiveGroup.container);
- $container.css("-moz-transition-property", "none");
+ $container.css("transition-property", "none");
currentActiveGroup.setPosition(40, 40, true);
currentActiveGroup.arrange({animate: false});
// move down 20 so we're far enough away from the top.
checkSnap(currentActiveGroup, 0, 20, contentWindow, function(snapped){
is(currentActiveGroup.getBounds().top, 60, "group.top is 60px");
ok(!snapped,"Move away from the edge");
--- a/browser/confvars.sh
+++ b/browser/confvars.sh
@@ -38,8 +38,9 @@ MOZ_APP_ID={ec8030f7-c20a-464f-9b0e-13a3
# of values.
ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-central
# The MAR_CHANNEL_ID must not contain the following 3 characters: ",\t "
MAR_CHANNEL_ID=firefox-mozilla-central
MOZ_PROFILE_MIGRATOR=1
MOZ_EXTENSION_MANAGER=1
MOZ_APP_STATIC_INI=1
MOZ_WEBAPP_RUNTIME=1
+MOZ_MEDIA_NAVIGATOR=1
--- a/browser/devtools/commandline/GcliCommands.jsm
+++ b/browser/devtools/commandline/GcliCommands.jsm
@@ -18,23 +18,27 @@ XPCOMUtils.defineLazyModuleGetter(this,
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "LayoutHelpers",
"resource:///modules/devtools/LayoutHelpers.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "console",
"resource:///modules/devtools/Console.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
+ "resource://gre/modules/AddonManager.jsm");
+
let prefSvc = "@mozilla.org/preferences-service;1";
XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
let prefService = Cc[prefSvc].getService(Ci.nsIPrefService);
return prefService.getBranch(null).QueryInterface(Ci.nsIPrefBranch2);
});
Cu.import("resource:///modules/devtools/GcliTiltCommands.jsm", {});
+Cu.import("resource:///modules/devtools/GcliCookieCommands.jsm", {});
/**
* A place to store the names of the commands that we have added as a result of
* calling refreshAutoCommands(). Used by refreshAutoCommands to remove the
* added commands.
*/
let commands = [];
@@ -288,31 +292,25 @@ gcli.addCommand({
/**
* 'console clear' command
*/
gcli.addCommand({
name: "console clear",
description: gcli.lookup("consoleclearDesc"),
exec: function Command_consoleClear(args, context) {
- let window = context.environment.chromeDocument.defaultView;
- let hud = HUDService.getHudReferenceById(context.environment.hudId);
-
- // Use a timeout so we also clear the reporting of the clear command
- let threadManager = Cc["@mozilla.org/thread-manager;1"]
- .getService(Ci.nsIThreadManager);
- threadManager.mainThread.dispatch({
- run: function() {
- hud.gcliterm.clearOutput();
- }
- }, Ci.nsIThread.DISPATCH_NORMAL);
+ let window = context.environment.contentDocument.defaultView;
+ let hud = HUDService.getHudByWindow(window);
+ // hud will be null if the web console has not been opened for this window
+ if (hud) {
+ hud.jsterm.clearOutput();
+ }
}
});
-
/**
* 'console close' command
*/
gcli.addCommand({
name: "console close",
description: gcli.lookup("consolecloseDesc"),
exec: function Command_consoleClose(args, context) {
let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
@@ -328,16 +326,61 @@ gcli.addCommand({
description: gcli.lookup("consoleopenDesc"),
exec: function Command_consoleOpen(args, context) {
let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
HUDService.activateHUDForContext(tab);
}
});
/**
+ * Restart command
+ *
+ * @param boolean nocache
+ * Disables loading content from cache upon restart.
+ *
+ * Examples :
+ * >> restart
+ * - restarts browser immediately
+ * >> restart --nocache
+ * - restarts immediately and starts Firefox without using cache
+ */
+gcli.addCommand({
+ name: "restart",
+ description: gcli.lookup("restartFirefoxDesc"),
+ params: [
+ {
+ name: "nocache",
+ type: "boolean",
+ defaultValue: false,
+ description: gcli.lookup("restartFirefoxNocacheDesc")
+ }
+ ],
+ returnType: "string",
+ exec: function Restart(args, context) {
+ let canceled = Cc["@mozilla.org/supports-PRBool;1"]
+ .createInstance(Ci.nsISupportsPRBool);
+ Services.obs.notifyObservers(canceled, "quit-application-requested", "restart");
+ if (canceled.data) {
+ return gcli.lookup("restartFirefoxRequestCancelled");
+ }
+
+ // disable loading content from cache.
+ if (args.nocache) {
+ Services.appinfo.invalidateCachesOnRestart();
+ }
+
+ // restart
+ Cc['@mozilla.org/toolkit/app-startup;1']
+ .getService(Ci.nsIAppStartup)
+ .quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
+ return gcli.lookup("restartFirefoxRestarting");
+ }
+});
+
+/**
* 'inspect' command
*/
gcli.addCommand({
name: "inspect",
description: gcli.lookup("inspectDesc"),
manual: gcli.lookup("inspectManual"),
params: [
{
@@ -537,8 +580,620 @@ gcli.addCommand({
});
} catch (ex) {
// If the debugger has been closed already, don't scare the user.
promise.resolve(gcli.lookup("breakdelRemoved"));
}
return promise;
}
});
+
+/**
+ * 'export' command
+ */
+gcli.addCommand({
+ name: "export",
+ description: gcli.lookup("exportDesc"),
+});
+
+/**
+ * The 'export html' command. This command allows the user to export the page to
+ * HTML after they do DOM changes.
+ */
+gcli.addCommand({
+ name: "export html",
+ description: gcli.lookup("exportHtmlDesc"),
+ exec: function(args, context) {
+ let document = context.environment.contentDocument;
+ let window = document.defaultView;
+ let page = document.documentElement.outerHTML;
+ window.open('data:text/plain;charset=utf8,' + encodeURIComponent(page));
+ }
+});
+
+/**
+ * 'pagemod' command
+ */
+gcli.addCommand({
+ name: "pagemod",
+ description: gcli.lookup("pagemodDesc"),
+});
+
+/**
+ * The 'pagemod replace' command. This command allows the user to search and
+ * replace within text nodes and attributes.
+ */
+gcli.addCommand({
+ name: "pagemod replace",
+ description: gcli.lookup("pagemodReplaceDesc"),
+ params: [
+ {
+ name: "search",
+ type: "string",
+ description: gcli.lookup("pagemodReplaceSearchDesc"),
+ },
+ {
+ name: "replace",
+ type: "string",
+ description: gcli.lookup("pagemodReplaceReplaceDesc"),
+ },
+ {
+ name: "ignoreCase",
+ type: "boolean",
+ description: gcli.lookup("pagemodReplaceIgnoreCaseDesc"),
+ },
+ {
+ name: "selector",
+ type: "string",
+ description: gcli.lookup("pagemodReplaceSelectorDesc"),
+ defaultValue: "*:not(script):not(style):not(embed):not(object):not(frame):not(iframe):not(frameset)",
+ },
+ {
+ name: "root",
+ type: "node",
+ description: gcli.lookup("pagemodReplaceRootDesc"),
+ defaultValue: null,
+ },
+ {
+ name: "attrOnly",
+ type: "boolean",
+ description: gcli.lookup("pagemodReplaceAttrOnlyDesc"),
+ },
+ {
+ name: "contentOnly",
+ type: "boolean",
+ description: gcli.lookup("pagemodReplaceContentOnlyDesc"),
+ },
+ {
+ name: "attributes",
+ type: "string",
+ description: gcli.lookup("pagemodReplaceAttributesDesc"),
+ defaultValue: null,
+ },
+ ],
+ exec: function(args, context) {
+ let document = context.environment.contentDocument;
+ let searchTextNodes = !args.attrOnly;
+ let searchAttributes = !args.contentOnly;
+ let regexOptions = args.ignoreCase ? 'ig' : 'g';
+ let search = new RegExp(escapeRegex(args.search), regexOptions);
+ let attributeRegex = null;
+ if (args.attributes) {
+ attributeRegex = new RegExp(args.attributes, regexOptions);
+ }
+
+ let root = args.root || document;
+ let elements = root.querySelectorAll(args.selector);
+ elements = Array.prototype.slice.call(elements);
+
+ let replacedTextNodes = 0;
+ let replacedAttributes = 0;
+
+ function replaceAttribute() {
+ replacedAttributes++;
+ return args.replace;
+ }
+ function replaceTextNode() {
+ replacedTextNodes++;
+ return args.replace;
+ }
+
+ for (let i = 0; i < elements.length; i++) {
+ let element = elements[i];
+ if (searchTextNodes) {
+ for (let y = 0; y < element.childNodes.length; y++) {
+ let node = element.childNodes[y];
+ if (node.nodeType == node.TEXT_NODE) {
+ node.textContent = node.textContent.replace(search, replaceTextNode);
+ }
+ }
+ }
+
+ if (searchAttributes) {
+ if (!element.attributes) {
+ continue;
+ }
+ for (let y = 0; y < element.attributes.length; y++) {
+ let attr = element.attributes[y];
+ if (!attributeRegex || attributeRegex.test(attr.name)) {
+ attr.value = attr.value.replace(search, replaceAttribute);
+ }
+ }
+ }
+ }
+
+ return gcli.lookupFormat("pagemodReplaceResult",
+ [elements.length, replacedTextNodes,
+ replacedAttributes]);
+ }
+});
+
+/**
+ * 'pagemod remove' command
+ */
+gcli.addCommand({
+ name: "pagemod remove",
+ description: gcli.lookup("pagemodRemoveDesc"),
+});
+
+
+/**
+ * The 'pagemod remove element' command.
+ */
+gcli.addCommand({
+ name: "pagemod remove element",
+ description: gcli.lookup("pagemodRemoveElementDesc"),
+ params: [
+ {
+ name: "search",
+ type: "string",
+ description: gcli.lookup("pagemodRemoveElementSearchDesc"),
+ },
+ {
+ name: "root",
+ type: "node",
+ description: gcli.lookup("pagemodRemoveElementRootDesc"),
+ defaultValue: null,
+ },
+ {
+ name: 'stripOnly',
+ type: 'boolean',
+ description: gcli.lookup("pagemodRemoveElementStripOnlyDesc"),
+ },
+ {
+ name: 'ifEmptyOnly',
+ type: 'boolean',
+ description: gcli.lookup("pagemodRemoveElementIfEmptyOnlyDesc"),
+ },
+ ],
+ exec: function(args, context) {
+ let document = context.environment.contentDocument;
+ let root = args.root || document;
+ let elements = Array.prototype.slice.call(root.querySelectorAll(args.search));
+
+ let removed = 0;
+ for (let i = 0; i < elements.length; i++) {
+ let element = elements[i];
+ let parentNode = element.parentNode;
+ if (!parentNode || !element.removeChild) {
+ continue;
+ }
+ if (args.stripOnly) {
+ while (element.hasChildNodes()) {
+ parentNode.insertBefore(element.childNodes[0], element);
+ }
+ }
+ if (!args.ifEmptyOnly || !element.hasChildNodes()) {
+ element.parentNode.removeChild(element);
+ removed++;
+ }
+ }
+
+ return gcli.lookupFormat("pagemodRemoveElementResultMatchedAndRemovedElements",
+ [elements.length, removed]);
+ }
+});
+
+/**
+ * The 'pagemod remove attribute' command.
+ */
+gcli.addCommand({
+ name: "pagemod remove attribute",
+ description: gcli.lookup("pagemodRemoveAttributeDesc"),
+ params: [
+ {
+ name: "searchAttributes",
+ type: "string",
+ description: gcli.lookup("pagemodRemoveAttributeSearchAttributesDesc"),
+ },
+ {
+ name: "searchElements",
+ type: "string",
+ description: gcli.lookup("pagemodRemoveAttributeSearchElementsDesc"),
+ },
+ {
+ name: "root",
+ type: "node",
+ description: gcli.lookup("pagemodRemoveAttributeRootDesc"),
+ defaultValue: null,
+ },
+ {
+ name: "ignoreCase",
+ type: "boolean",
+ description: gcli.lookup("pagemodRemoveAttributeIgnoreCaseDesc"),
+ },
+ ],
+ exec: function(args, context) {
+ let document = context.environment.contentDocument;
+
+ let root = args.root || document;
+ let regexOptions = args.ignoreCase ? 'ig' : 'g';
+ let attributeRegex = new RegExp(args.searchAttributes, regexOptions);
+ let elements = root.querySelectorAll(args.searchElements);
+ elements = Array.prototype.slice.call(elements);
+
+ let removed = 0;
+ for (let i = 0; i < elements.length; i++) {
+ let element = elements[i];
+ if (!element.attributes) {
+ continue;
+ }
+
+ var attrs = Array.prototype.slice.call(element.attributes);
+ for (let y = 0; y < attrs.length; y++) {
+ let attr = attrs[y];
+ if (attributeRegex.test(attr.name)) {
+ element.removeAttribute(attr.name);
+ removed++;
+ }
+ }
+ }
+
+ return gcli.lookupFormat("pagemodRemoveAttributeResult",
+ [elements.length, removed]);
+ }
+});
+
+
+/**
+ * Make a given string safe to use in a regular expression.
+ *
+ * @param string aString
+ * The string you want to use in a regex.
+ * @return string
+ * The equivalent of |aString| but safe to use in a regex.
+ */
+function escapeRegex(aString) {
+ return aString.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
+}
+
+/**
+ * 'addon' command.
+ */
+gcli.addCommand({
+ name: "addon",
+ description: gcli.lookup("addonDesc")
+});
+
+/**
+ * 'addon list' command.
+ */
+gcli.addCommand({
+ name: "addon list",
+ description: gcli.lookup("addonListDesc"),
+ params: [{
+ name: 'type',
+ type: {
+ name: 'selection',
+ data: ["dictionary", "extension", "locale", "plugin", "theme", "all"]
+ },
+ defaultValue: 'all',
+ description: gcli.lookup("addonListTypeDesc"),
+ }],
+ exec: function(aArgs, context) {
+ function representEnabledAddon(aAddon) {
+ return "<li><![CDATA[" + aAddon.name + "\u2002" + aAddon.version +
+ getAddonStatus(aAddon) + "]]></li>";
+ }
+
+ function representDisabledAddon(aAddon) {
+ return "<li class=\"gcli-addon-disabled\">" +
+ "<![CDATA[" + aAddon.name + "\u2002" + aAddon.version + aAddon.version +
+ "]]></li>";
+ }
+
+ function getAddonStatus(aAddon) {
+ let operations = [];
+
+ if (aAddon.pendingOperations & AddonManager.PENDING_ENABLE) {
+ operations.push("PENDING_ENABLE");
+ }
+
+ if (aAddon.pendingOperations & AddonManager.PENDING_DISABLE) {
+ operations.push("PENDING_DISABLE");
+ }
+
+ if (aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL) {
+ operations.push("PENDING_UNINSTALL");
+ }
+
+ if (aAddon.pendingOperations & AddonManager.PENDING_INSTALL) {
+ operations.push("PENDING_INSTALL");
+ }
+
+ if (aAddon.pendingOperations & AddonManager.PENDING_UPGRADE) {
+ operations.push("PENDING_UPGRADE");
+ }
+
+ if (operations.length) {
+ return " (" + operations.join(", ") + ")";
+ }
+ return "";
+ }
+
+ /**
+ * Compares two addons by their name. Used in sorting.
+ */
+ function compareAddonNames(aNameA, aNameB) {
+ return String.localeCompare(aNameA.name, aNameB.name);
+ }
+
+ /**
+ * Resolves the promise which is the scope (this) of this function, filling
+ * it with an HTML representation of the passed add-ons.
+ */
+ function list(aType, aAddons) {
+ if (!aAddons.length) {
+ this.resolve(gcli.lookup("addonNoneOfType"));
+ }
+
+ // Separate the enabled add-ons from the disabled ones.
+ let enabledAddons = [];
+ let disabledAddons = [];
+
+ aAddons.forEach(function(aAddon) {
+ if (aAddon.isActive) {
+ enabledAddons.push(aAddon);
+ } else {
+ disabledAddons.push(aAddon);
+ }
+ });
+
+ let header;
+ switch(aType) {
+ case "dictionary":
+ header = gcli.lookup("addonListDictionaryHeading");
+ break;
+ case "extension":
+ header = gcli.lookup("addonListExtensionHeading");
+ break;
+ case "locale":
+ header = gcli.lookup("addonListLocaleHeading");
+ break;
+ case "plugin":
+ header = gcli.lookup("addonListPluginHeading");
+ break;
+ case "theme":
+ header = gcli.lookup("addonListThemeHeading");
+ case "all":
+ header = gcli.lookup("addonListAllHeading");
+ break;
+ default:
+ header = gcli.lookup("addonListUnknownHeading");
+ }
+
+ // Map and sort the add-ons, and create an HTML list.
+ this.resolve(header +
+ "<ol>" +
+ enabledAddons.sort(compareAddonNames).map(representEnabledAddon).join("") +
+ disabledAddons.sort(compareAddonNames).map(representDisabledAddon).join("") +
+ "</ol>");
+ }
+
+ // Create the promise that will be resolved when the add-on listing has
+ // been finished.
+ let promise = context.createPromise();
+ let types = aArgs.type == "all" ? null : [aArgs.type];
+ AddonManager.getAddonsByTypes(types, list.bind(promise, aArgs.type));
+ return promise;
+ }
+});
+
+// We need a list of addon names for the enable and disable commands. Because
+// getting the name list is async we do not add the commands until we have the
+// list.
+AddonManager.getAllAddons(function addonAsync(aAddons) {
+ // We listen for installs to keep our addon list up to date. There is no need
+ // to listen for uninstalls because uninstalled addons are simply disabled
+ // until restart (to enable undo functionality).
+ AddonManager.addAddonListener({
+ onInstalled: function(aAddon) {
+ addonNameCache.push({
+ name: representAddon(aAddon).replace(/\s/g, "_"),
+ value: aAddon.name
+ });
+ },
+ onUninstalled: function(aAddon) {
+ let name = representAddon(aAddon).replace(/\s/g, "_");
+
+ for (let i = 0; i < addonNameCache.length; i++) {
+ if(addonNameCache[i].name == name) {
+ addonNameCache.splice(i, 1);
+ break;
+ }
+ }
+ },
+ });
+
+ /**
+ * Returns a string that represents the passed add-on.
+ */
+ function representAddon(aAddon) {
+ let name = aAddon.name + " " + aAddon.version;
+ return name.trim();
+ }
+
+ let addonNameCache = [];
+
+ // The name parameter, used in "addon enable" and "addon disable."
+ let nameParameter = {
+ name: "name",
+ type: {
+ name: "selection",
+ lookup: addonNameCache
+ },
+ description: gcli.lookup("addonNameDesc")
+ };
+
+ for (let addon of aAddons) {
+ addonNameCache.push({
+ name: representAddon(addon).replace(/\s/g, "_"),
+ value: addon.name
+ });
+ }
+
+ /**
+ * 'addon enable' command.
+ */
+ gcli.addCommand({
+ name: "addon enable",
+ description: gcli.lookup("addonEnableDesc"),
+ params: [nameParameter],
+ exec: function(aArgs, context) {
+ /**
+ * Enables the addon in the passed list which has a name that matches
+ * according to the passed name comparer, and resolves the promise which
+ * is the scope (this) of this function to display the result of this
+ * enable attempt.
+ */
+ function enable(aName, addons) {
+ // Find the add-on.
+ let addon = null;
+ addons.some(function(candidate) {
+ if (candidate.name == aName) {
+ addon = candidate;
+ return true;
+ } else {
+ return false;
+ }
+ });
+
+ let name = representAddon(addon);
+
+ if (!addon.userDisabled) {
+ this.resolve("<![CDATA[" +
+ gcli.lookupFormat("addonAlreadyEnabled", [name]) + "]]>");
+ } else {
+ addon.userDisabled = false;
+ // nl-nl: {$1} is ingeschakeld.
+ this.resolve("<![CDATA[" +
+ gcli.lookupFormat("addonEnabled", [name]) + "]]>");
+ }
+ }
+
+ let promise = context.createPromise();
+ // List the installed add-ons, enable one when done listing.
+ AddonManager.getAllAddons(enable.bind(promise, aArgs.name));
+ return promise;
+ }
+ });
+
+ /**
+ * 'addon disable' command.
+ */
+ gcli.addCommand({
+ name: "addon disable",
+ description: gcli.lookup("addonDisableDesc"),
+ params: [nameParameter],
+ exec: function(aArgs, context) {
+ /**
+ * Like enable, but ... you know ... the exact opposite.
+ */
+ function disable(aName, addons) {
+ // Find the add-on.
+ let addon = null;
+ addons.some(function(candidate) {
+ if (candidate.name == aName) {
+ addon = candidate;
+ return true;
+ } else {
+ return false;
+ }
+ });
+
+ let name = representAddon(addon);
+
+ if (addon.userDisabled) {
+ this.resolve("<![CDATA[" +
+ gcli.lookupFormat("addonAlreadyDisabled", [name]) + "]]>");
+ } else {
+ addon.userDisabled = true;
+ // nl-nl: {$1} is uitgeschakeld.
+ this.resolve("<![CDATA[" +
+ gcli.lookupFormat("addonDisabled", [name]) + "]]>");
+ }
+ }
+
+ let promise = context.createPromise();
+ // List the installed add-ons, disable one when done listing.
+ AddonManager.getAllAddons(disable.bind(promise, aArgs.name));
+ return promise;
+ }
+ });
+ Services.obs.notifyObservers(null, "gcli_addon_commands_ready", null);
+});
+
+/* Responsive Mode commands */
+(function gcli_cmd_resize_container() {
+ function gcli_cmd_resize(args, context) {
+ let browserDoc = context.environment.chromeDocument;
+ let browserWindow = browserDoc.defaultView;
+ let mgr = browserWindow.ResponsiveUI.ResponsiveUIManager;
+ mgr.handleGcliCommand(browserWindow,
+ browserWindow.gBrowser.selectedTab,
+ this.name,
+ args);
+ }
+
+ gcli.addCommand({
+ name: 'resize',
+ description: gcli.lookup('resizeModeDesc')
+ });
+
+ gcli.addCommand({
+ name: 'resize on',
+ description: gcli.lookup('resizeModeOnDesc'),
+ manual: gcli.lookup('resizeModeManual'),
+ exec: gcli_cmd_resize
+ });
+
+ gcli.addCommand({
+ name: 'resize off',
+ description: gcli.lookup('resizeModeOffDesc'),
+ manual: gcli.lookup('resizeModeManual'),
+ exec: gcli_cmd_resize
+ });
+
+ gcli.addCommand({
+ name: 'resize toggle',
+ description: gcli.lookup('resizeModeToggleDesc'),
+ manual: gcli.lookup('resizeModeManual'),
+ exec: gcli_cmd_resize
+ });
+
+ gcli.addCommand({
+ name: 'resize to',
+ description: gcli.lookup('resizeModeToDesc'),
+ params: [
+ {
+ name: 'width',
+ type: 'number',
+ description: gcli.lookup("resizePageArgWidthDesc"),
+ },
+ {
+ name: 'height',
+ type: 'number',
+ description: gcli.lookup("resizePageArgHeightDesc"),
+ },
+ ],
+ exec: gcli_cmd_resize
+ });
+})();
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/GcliCookieCommands.jsm
@@ -0,0 +1,204 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+let EXPORTED_SYMBOLS = [ ];
+
+Components.utils.import("resource:///modules/devtools/gcli.jsm");
+
+
+// We should really be using nsICookieManager so we can read more than just the
+// key/value of cookies. The difficulty is filtering the cookies that are
+// relevant to the current page. See
+// https://github.com/firebug/firebug/blob/master/extension/content/firebug/cookies/cookieObserver.js#L123
+// For details on how this is done with Firebug
+
+/**
+ * 'cookie' command
+ */
+gcli.addCommand({
+ name: "cookie",
+ description: gcli.lookup("cookieDesc"),
+ manual: gcli.lookup("cookieManual")
+});
+
+/**
+ * The template for the 'cookie list' command.
+ */
+var cookieListHtml = "" +
+ "<table>" +
+ " <tr>" +
+ " <th>" + gcli.lookup("cookieListOutKey") + "</th>" +
+ " <th>" + gcli.lookup("cookieListOutValue") + "</th>" +
+ " <th>" + gcli.lookup("cookieListOutActions") + "</th>" +
+ " </tr>" +
+ " <tr foreach='cookie in ${cookies}'>" +
+ " <td>${cookie.key}</td>" +
+ " <td>${cookie.value}</td>" +
+ " <td>" +
+ " <span class='gcli-out-shortcut'" +
+ " onclick='${onclick}' ondblclick='${ondblclick}'" +
+ " data-command='cookie set ${cookie.key}'" +
+ " >" + gcli.lookup("cookieListOutEdit") + "</span>" +
+ " <span class='gcli-out-shortcut'" +
+ " onclick='${onclick}' ondblclick='${ondblclick}'" +
+ " data-command='cookie remove ${cookie.key}'" +
+ " >" + gcli.lookup("cookieListOutRemove") + "</span>" +
+ " </td>" +
+ " </tr>" +
+ "</table>" +
+ "";
+
+/**
+ * 'cookie list' command
+ */
+gcli.addCommand({
+ name: "cookie list",
+ description: gcli.lookup("cookieListDesc"),
+ manual: gcli.lookup("cookieListManual"),
+ returnType: "string",
+ exec: function Command_cookieList(args, context) {
+ // Parse out an array of { key:..., value:... } objects for each cookie
+ var doc = context.environment.contentDocument;
+ var cookies = doc.cookie.split("; ").map(function(cookieStr) {
+ var equalsPos = cookieStr.indexOf("=");
+ return {
+ key: cookieStr.substring(0, equalsPos),
+ value: cookieStr.substring(equalsPos + 1)
+ };
+ });
+
+ return context.createView({
+ html: cookieListHtml,
+ data: {
+ cookies: cookies,
+ onclick: createUpdateHandler(context),
+ ondblclick: createExecuteHandler(context),
+ }
+ });
+ }
+});
+
+/**
+ * 'cookie remove' command
+ */
+gcli.addCommand({
+ name: "cookie remove",
+ description: gcli.lookup("cookieRemoveDesc"),
+ manual: gcli.lookup("cookieRemoveManual"),
+ params: [
+ {
+ name: "key",
+ type: "string",
+ description: gcli.lookup("cookieRemoveKeyDesc"),
+ }
+ ],
+ exec: function Command_cookieRemove(args, context) {
+ let document = context.environment.contentDocument;
+ let expDate = new Date();
+ expDate.setDate(expDate.getDate() - 1);
+ document.cookie = escape(args.key) + "=; expires=" + expDate.toGMTString();
+ }
+});
+
+/**
+ * 'cookie set' command
+ */
+gcli.addCommand({
+ name: "cookie set",
+ description: gcli.lookup("cookieSetDesc"),
+ manual: gcli.lookup("cookieSetManual"),
+ params: [
+ {
+ name: "key",
+ type: "string",
+ description: gcli.lookup("cookieSetKeyDesc")
+ },
+ {
+ name: "value",
+ type: "string",
+ description: gcli.lookup("cookieSetValueDesc")
+ },
+ {
+ group: gcli.lookup("cookieSetOptionsDesc"),
+ params: [
+ {
+ name: "path",
+ type: "string",
+ defaultValue: "/",
+ description: gcli.lookup("cookieSetPathDesc")
+ },
+ {
+ name: "domain",
+ type: "string",
+ defaultValue: null,
+ description: gcli.lookup("cookieSetDomainDesc")
+ },
+ {
+ name: "secure",
+ type: "boolean",
+ description: gcli.lookup("cookieSetSecureDesc")
+ }
+ ]
+ }
+ ],
+ exec: function Command_cookieSet(args, context) {
+ let document = context.environment.contentDocument;
+
+ document.cookie = escape(args.key) + "=" + escape(args.value) +
+ (args.domain ? "; domain=" + args.domain : "") +
+ (args.path ? "; path=" + args.path : "") +
+ (args.secure ? "; secure" : "");
+ }
+});
+
+/**
+ * Helper to find the 'data-command' attribute and call some action on it.
+ * @see |updateCommand()| and |executeCommand()|
+ */
+function withCommand(element, action) {
+ var command = element.getAttribute("data-command");
+ if (!command) {
+ command = element.querySelector("*[data-command]")
+ .getAttribute("data-command");
+ }
+
+ if (command) {
+ action(command);
+ }
+ else {
+ console.warn("Missing data-command for " + util.findCssSelector(element));
+ }
+}
+
+/**
+ * Create a handler to update the requisition to contain the text held in the
+ * first matching data-command attribute under the currentTarget of the event.
+ * @param context Either a Requisition or an ExecutionContext or another object
+ * that contains an |update()| function that follows a similar contract.
+ */
+function createUpdateHandler(context) {
+ return function(ev) {
+ withCommand(ev.currentTarget, function(command) {
+ context.update(command);
+ });
+ }
+}
+
+/**
+ * Create a handler to execute the text held in the data-command attribute
+ * under the currentTarget of the event.
+ * @param context Either a Requisition or an ExecutionContext or another object
+ * that contains an |update()| function that follows a similar contract.
+ */
+function createExecuteHandler(context) {
+ return function(ev) {
+ withCommand(ev.currentTarget, function(command) {
+ context.exec({
+ visible: true,
+ typed: command
+ });
+ });
+ }
+}
--- a/browser/devtools/commandline/gcli.jsm
+++ b/browser/devtools/commandline/gcli.jsm
@@ -5287,24 +5287,24 @@ CommandAssignment.prototype.getStatus =
};
exports.CommandAssignment = CommandAssignment;
/**
* Special assignment used when ignoring parameters that don't have a home
*/
-function UnassignedAssignment(requisition, arg, isIncompleteName) {
+function UnassignedAssignment(requisition, arg) {
this.param = new canon.Parameter({
name: '__unassigned',
description: l10n.lookup('cliOptions'),
type: {
name: 'param',
requisition: requisition,
- isIncompleteName: isIncompleteName
+ isIncompleteName: (arg.text.charAt(0) === '-')
},
});
this.paramIndex = -1;
this.onAssignmentChange = util.createEvent('UnassignedAssignment.onAssignmentChange');
this.conversion = this.param.type.parse(arg);
this.conversion.assign(this);
}
@@ -5533,18 +5533,25 @@ Requisition.prototype.cloneAssignments =
* There is no such thing as an INCOMPLETE overall status because the
* definition of INCOMPLETE takes into account the cursor position to say 'this
* isn't quite ERROR because the user can fix it by typing', however overall,
* this is still an error status.
*/
Requisition.prototype.getStatus = function() {
var status = Status.VALID;
if (this._unassigned.length !== 0) {
- return Status.ERROR;
- }
+ var isAllIncomplete = true;
+ this._unassigned.forEach(function(assignment) {
+ if (!assignment.param.type.isIncompleteName) {
+ isAllIncomplete = false;
+ }
+ });
+ status = isAllIncomplete ? Status.INCOMPLETE : Status.ERROR;
+ }
+
this.getAssignments(true).forEach(function(assignment) {
var assignStatus = assignment.getStatus();
if (assignStatus > status) {
status = assignStatus;
}
}, this);
if (status === Status.INCOMPLETE) {
status = Status.ERROR;
@@ -6353,17 +6360,17 @@ Requisition.prototype._split = function(
// This could probably be re-written to consume args as we go
};
/**
* Add all the passed args to the list of unassigned assignments.
*/
Requisition.prototype._addUnassignedArgs = function(args) {
args.forEach(function(arg) {
- this._unassigned.push(new UnassignedAssignment(this, arg, false));
+ this._unassigned.push(new UnassignedAssignment(this, arg));
}.bind(this));
};
/**
* Work out which arguments are applicable to which parameters.
*/
Requisition.prototype._assign = function(args) {
this._unassigned = [];
@@ -6396,30 +6403,30 @@ Requisition.prototype._assign = function
var conversion = assignment.param.type.parse(arg);
assignment.setConversion(conversion);
return;
}
}
// Positional arguments can still be specified by name, but if they are
// then we need to ignore them when working them out positionally
- var names = this.getParameterNames();
+ var unassignedParams = this.getParameterNames();
// We collect the arguments used in arrays here before assigning
var arrayArgs = {};
// Extract all the named parameters
this.getAssignments(false).forEach(function(assignment) {
// Loop over the arguments
// Using while rather than loop because we remove args as we go
var i = 0;
while (i < args.length) {
if (assignment.param.isKnownAs(args[i].text)) {
var arg = args.splice(i, 1)[0];
- names = names.filter(function(test) {
+ unassignedParams = unassignedParams.filter(function(test) {
return test !== assignment.param.name;
});
// boolean parameters don't have values, default to false
if (assignment.param.type instanceof BooleanType) {
arg = new TrueNamedArgument(null, arg);
}
else {
@@ -6446,17 +6453,17 @@ Requisition.prototype._assign = function
else {
// Skip this parameter and handle as a positional parameter
i++;
}
}
}, this);
// What's left are positional parameters assign in order
- names.forEach(function(name) {
+ unassignedParams.forEach(function(name) {
var assignment = this.getAssignment(name);
// If not set positionally, and we can't set it non-positionally,
// we have to default it to prevent previous values surviving
if (!assignment.param.isPositionalAllowed) {
assignment.setBlank();
return;
}
@@ -6480,17 +6487,17 @@ Requisition.prototype._assign = function
var arg = args.splice(0, 1)[0];
// --foo and -f are named parameters, -4 is a number. So '-' is either
// the start of a named parameter or a number depending on the context
var isIncompleteName = assignment.param.type instanceof NumberType ?
/-[-a-zA-Z_]/.test(arg.text) :
arg.text.charAt(0) === '-';
if (isIncompleteName) {
- this._unassigned.push(new UnassignedAssignment(this, arg, true));
+ this._unassigned.push(new UnassignedAssignment(this, arg));
}
else {
var conversion = assignment.param.type.parse(arg);
assignment.setConversion(conversion);
}
}
}
}, this);
@@ -7038,16 +7045,20 @@ FocusManager.prototype._checkShow = func
}
};
/**
* Calculate if we should be showing or hidden taking into account all the
* available inputs
*/
FocusManager.prototype._shouldShowTooltip = function() {
+ if (!this._hasFocus) {
+ return { visible: false, reason: '!hasFocus' };
+ }
+
if (eagerHelper.value === Eagerness.NEVER) {
return { visible: false, reason: 'eagerHelper !== NEVER' };
}
if (eagerHelper.value === Eagerness.ALWAYS) {
return { visible: true, reason: 'eagerHelper !== ALWAYS' };
}
@@ -7066,16 +7077,20 @@ FocusManager.prototype._shouldShowToolti
return { visible: false, reason: 'default' };
};
/**
* Calculate if we should be showing or hidden taking into account all the
* available inputs
*/
FocusManager.prototype._shouldShowOutput = function() {
+ if (!this._hasFocus) {
+ return { visible: false, reason: '!hasFocus' };
+ }
+
if (this._recentOutput) {
return { visible: true, reason: 'recentOutput' };
}
return { visible: false, reason: 'default' };
};
exports.FocusManager = FocusManager;
@@ -9722,17 +9737,17 @@ Completer.prototype.update = function(ev
*/
Completer.prototype._getCompleterTemplateData = function() {
var input = this.inputter.getInputState();
// directTabText is for when the current input is a prefix of the completion
// arrowTabText is for when we need to use an -> to show what will be used
var directTabText = '';
var arrowTabText = '';
- var current = this.inputter.assignment;
+ var current = this.requisition.getAssignmentAt(input.cursor.start);
if (input.typed.trim().length !== 0) {
var prediction = current.conversion.getPredictionAt(this.choice);
if (prediction) {
var tabText = prediction.name;
var existing = current.arg.text;
if (existing !== tabText) {
--- a/browser/devtools/commandline/test/Makefile.in
+++ b/browser/devtools/commandline/test/Makefile.in
@@ -7,29 +7,35 @@ DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = browser/devtools/commandline/test
include $(DEPTH)/config/autoconf.mk
MOCHITEST_BROWSER_FILES = \
+ browser_gcli_addon.js \
browser_gcli_break.js \
browser_gcli_commands.js \
+ browser_gcli_cookie.js \
browser_gcli_edit.js \
browser_gcli_inspect.js \
browser_gcli_integrate.js \
+ browser_gcli_pagemod_export.js \
browser_gcli_pref.js \
+ browser_gcli_responsivemode.js \
+ browser_gcli_restart.js \
browser_gcli_settings.js \
browser_gcli_web.js \
head.js \
$(NULL)
MOCHITEST_BROWSER_FILES += \
browser_gcli_break.html \
browser_gcli_inspect.html \
resources_inpage.js \
resources_inpage1.css \
resources_inpage2.css \
resources.html \
$(NULL)
include $(topsrcdir)/config/rules.mk
+
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_addon.js
@@ -0,0 +1,43 @@
+function test() {
+ DeveloperToolbarTest.test("about:blank", function GAT_test() {
+ function GAT_ready() {
+ Services.obs.removeObserver(GAT_ready, "gcli_addon_commands_ready", false);
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "addon list dictionary",
+ status: "VALID"
+ });
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "addon list extension",
+ status: "VALID"
+ });
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "addon list locale",
+ status: "VALID"
+ });
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "addon list plugin",
+ status: "VALID"
+ });
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "addon list theme",
+ status: "VALID"
+ });
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "addon list all",
+ status: "VALID"
+ });
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "addon disable Test_Plug-in_1.0.0.0",
+ status: "VALID"
+ });
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "addon enable Test_Plug-in_1.0.0.0",
+ status: "VALID"
+ });
+ DeveloperToolbarTest.exec({ completed: false });
+ finish();
+ }
+ Services.obs.addObserver(GAT_ready, "gcli_addon_commands_ready", false);
+ });
+}
--- a/browser/devtools/commandline/test/browser_gcli_commands.js
+++ b/browser/devtools/commandline/test/browser_gcli_commands.js
@@ -6,50 +6,59 @@
let imported = {};
Components.utils.import("resource:///modules/HUDService.jsm", imported);
const TEST_URI = "data:text/html;charset=utf-8,gcli-commands";
function test() {
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
testEcho();
- testConsoleClear();
- testConsoleOpenClose(tab);
+ testConsole(tab);
imported = undefined;
finish();
});
}
function testEcho() {
DeveloperToolbarTest.exec({
typed: "echo message",
args: { message: "message" },
outputMatch: /^message$/,
});
}
-function testConsoleClear() {
- DeveloperToolbarTest.exec({
- typed: "console clear",
- args: {},
- blankOutput: true,
- });
-}
-
-function testConsoleOpenClose(tab) {
+function testConsole(tab) {
DeveloperToolbarTest.exec({
typed: "console open",
args: {},
blankOutput: true,
});
let hud = imported.HUDService.getHudByWindow(content);
ok(hud.hudId in imported.HUDService.hudReferences, "console open");
+ hud.jsterm.execute("pprint(window)");
+
+ /*
+ // The web console is async and we can't force it with hud._flushMessageQueue
+ // So we are skipping the test for output until we have an event to wait on
+ let labels = hud.jsterm.outputNode.querySelectorAll(".webconsole-msg-output");
+ ok(labels.length > 0, "output for pprint(window)");
+ */
+
+ DeveloperToolbarTest.exec({
+ typed: "console clear",
+ args: {},
+ blankOutput: true,
+ });
+
+ let labels = hud.jsterm.outputNode.querySelectorAll(".webconsole-msg-output");
+ is(labels.length, 0, "no output in console");
+
DeveloperToolbarTest.exec({
typed: "console close",
args: {},
blankOutput: true,
});
ok(!(hud.hudId in imported.HUDService.hudReferences), "console closed");
}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_cookie.js
@@ -0,0 +1,68 @@
+/* Any copyright is dedicated to the Public Domain.
+* http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the cookie commands works as they should
+
+const TEST_URI = "data:text/html;charset=utf-8,gcli-cookie";
+
+function test() {
+ DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+ testCookieCommands();
+ finish();
+ });
+}
+
+function testCookieCommands() {
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "cook",
+ directTabText: "ie",
+ status: "ERROR"
+ });
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "cookie l",
+ directTabText: "ist",
+ status: "ERROR"
+ });
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "cookie list",
+ status: "VALID",
+ emptyParameters: [ ]
+ });
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "cookie remove",
+ status: "ERROR",
+ emptyParameters: [ " <key>" ]
+ });
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "cookie set",
+ status: "ERROR",
+ emptyParameters: [ " <key>", " <value>" ],
+ });
+
+ DeveloperToolbarTest.exec({
+ typed: "cookie set fruit banana",
+ args: {
+ key: "fruit",
+ value: "banana",
+ path: "/",
+ domain: null,
+ secure: false
+ },
+ blankOutput: true,
+ });
+
+ DeveloperToolbarTest.exec({
+ typed: "cookie list",
+ outputMatch: /Key/
+ });
+
+ DeveloperToolbarTest.exec({
+ typed: "cookie remove fruit",
+ args: { key: "fruit" },
+ blankOutput: true,
+ });
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_pagemod_export.js
@@ -0,0 +1,272 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the inspect command works as it should
+
+const TEST_URI = "http://example.com/browser/browser/devtools/commandline/test/browser_gcli_inspect.html";
+
+function test() {
+ let initialHtml = "";
+
+ DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+ initialHtml = content.document.documentElement.innerHTML;
+
+ testExportHtml();
+ testPageModReplace();
+ testPageModRemoveElement();
+ testPageModRemoveAttribute();
+ finish();
+ });
+
+ function testExportHtml() {
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "export html",
+ status: "VALID"
+ });
+
+ let oldOpen = content.open;
+ let openURL = "";
+ content.open = function(aUrl) {
+ openURL = aUrl;
+ };
+
+ DeveloperToolbarTest.exec({ blankOutput: true });
+
+ openURL = decodeURIComponent(openURL);
+
+ isnot(openURL.indexOf('<html lang="en">'), -1, "export html works: <html>");
+ isnot(openURL.indexOf("<title>GCLI"), -1, "export html works: <title>");
+ isnot(openURL.indexOf('<p id="someid">#'), -1, "export html works: <p>");
+
+ content.open = oldOpen;
+ }
+
+ function getContent() {
+ return content.document.documentElement.innerHTML;
+ }
+
+ function resetContent() {
+ content.document.documentElement.innerHTML = initialHtml;
+ }
+
+ function testPageModReplace() {
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "pagemod replace",
+ emptyParameters: [" <search>", " <replace>", " [ignoreCase]",
+ " [selector]", " [root]", " [attrOnly]",
+ " [contentOnly]", " [attributes]"],
+ status: "ERROR"
+ });
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "pagemod replace some foo",
+ emptyParameters: [" [ignoreCase]", " [selector]", " [root]",
+ " [attrOnly]", " [contentOnly]", " [attributes]"],
+ status: "VALID"
+ });
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "pagemod replace some foo true",
+ emptyParameters: [" [selector]", " [root]", " [attrOnly]",
+ " [contentOnly]", " [attributes]"],
+ status: "VALID"
+ });
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "pagemod replace some foo true --attrOnly",
+ emptyParameters: [" [selector]", " [root]", " [contentOnly]",
+ " [attributes]"],
+ status: "VALID"
+ });
+
+ DeveloperToolbarTest.exec({
+ typed: "pagemod replace sOme foOBar",
+ outputMatch: /^[^:]+: 13\. [^:]+: 0\. [^:]+: 0\.\s*$/
+ });
+
+ is(getContent(), initialHtml, "no change in the page");
+
+ DeveloperToolbarTest.exec({
+ typed: "pagemod replace sOme foOBar true",
+ outputMatch: /^[^:]+: 13\. [^:]+: 2\. [^:]+: 2\.\s*$/
+ });
+
+ isnot(getContent().indexOf('<p class="foOBarclass">.foOBarclass'), -1,
+ ".someclass changed to .foOBarclass");
+ isnot(getContent().indexOf('<p id="foOBarid">#foOBarid'), -1,
+ "#someid changed to #foOBarid");
+
+ resetContent();
+
+ DeveloperToolbarTest.exec({
+ typed: "pagemod replace some foobar --contentOnly",
+ outputMatch: /^[^:]+: 13\. [^:]+: 2\. [^:]+: 0\.\s*$/
+ });
+
+ isnot(getContent().indexOf('<p class="someclass">.foobarclass'), -1,
+ ".someclass changed to .foobarclass (content only)");
+ isnot(getContent().indexOf('<p id="someid">#foobarid'), -1,
+ "#someid changed to #foobarid (content only)");
+
+ resetContent();
+
+ DeveloperToolbarTest.exec({
+ typed: "pagemod replace some foobar --attrOnly",
+ outputMatch: /^[^:]+: 13\. [^:]+: 0\. [^:]+: 2\.\s*$/
+ });
+
+ isnot(getContent().indexOf('<p class="foobarclass">.someclass'), -1,
+ ".someclass changed to .foobarclass (attr only)");
+ isnot(getContent().indexOf('<p id="foobarid">#someid'), -1,
+ "#someid changed to #foobarid (attr only)");
+
+ resetContent();
+
+ DeveloperToolbarTest.exec({
+ typed: "pagemod replace some foobar --root head",
+ outputMatch: /^[^:]+: 2\. [^:]+: 0\. [^:]+: 0\.\s*$/
+ });
+
+ is(getContent(), initialHtml, "nothing changed");
+
+ DeveloperToolbarTest.exec({
+ typed: "pagemod replace some foobar --selector .someclass,div,span",
+ outputMatch: /^[^:]+: 4\. [^:]+: 1\. [^:]+: 1\.\s*$/
+ });
+
+ isnot(getContent().indexOf('<p class="foobarclass">.foobarclass'), -1,
+ ".someclass changed to .foobarclass");
+ isnot(getContent().indexOf('<p id="someid">#someid'), -1,
+ "#someid did not change");
+
+ resetContent();
+ }
+
+ function testPageModRemoveElement() {
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "pagemod remove",
+ status: "ERROR"
+ });
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "pagemod remove element",
+ emptyParameters: [" <search>", " [root]", " [stripOnly]", " [ifEmptyOnly]"],
+ status: "ERROR"
+ });
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "pagemod remove element foo",
+ emptyParameters: [" [root]", " [stripOnly]", " [ifEmptyOnly]"],
+ status: "VALID"
+ });
+
+ DeveloperToolbarTest.exec({
+ typed: "pagemod remove element p",
+ outputMatch: /^[^:]+: 3\. [^:]+: 3\.\s*$/
+ });
+
+ is(getContent().indexOf('<p class="someclass">'), -1, "p.someclass removed");
+ is(getContent().indexOf('<p id="someid">'), -1, "p#someid removed");
+ is(getContent().indexOf("<p><strong>"), -1, "<p> wrapping <strong> removed");
+ isnot(getContent().indexOf("<span>"), -1, "<span> not removed");
+
+ resetContent();
+
+ DeveloperToolbarTest.exec({
+ typed: "pagemod remove element p head",
+ outputMatch: /^[^:]+: 0\. [^:]+: 0\.\s*$/
+ });
+
+ is(getContent(), initialHtml, "nothing changed in the page");
+
+ DeveloperToolbarTest.exec({
+ typed: "pagemod remove element p --ifEmptyOnly",
+ outputMatch: /^[^:]+: 3\. [^:]+: 0\.\s*$/
+ });
+
+ is(getContent(), initialHtml, "nothing changed in the page");
+
+ DeveloperToolbarTest.exec({
+ typed: "pagemod remove element meta,title --ifEmptyOnly",
+ outputMatch: /^[^:]+: 2\. [^:]+: 1\.\s*$/
+ });
+
+ is(getContent().indexOf("<meta charset="), -1, "<meta> removed");
+ isnot(getContent().indexOf("<title>"), -1, "<title> not removed");
+
+ resetContent();
+
+ DeveloperToolbarTest.exec({
+ typed: "pagemod remove element p --stripOnly",
+ outputMatch: /^[^:]+: 3\. [^:]+: 3\.\s*$/
+ });
+
+ is(getContent().indexOf('<p class="someclass">'), -1, "p.someclass removed");
+ is(getContent().indexOf('<p id="someid">'), -1, "p#someid removed");
+ is(getContent().indexOf("<p><strong>"), -1, "<p> wrapping <strong> removed");
+ isnot(getContent().indexOf(".someclass"), -1, ".someclass still exists");
+ isnot(getContent().indexOf("#someid"), -1, "#someid still exists");
+ isnot(getContent().indexOf("<strong>p"), -1, "<strong> still exists");
+
+ resetContent();
+ }
+
+ function testPageModRemoveAttribute() {
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "pagemod remove attribute",
+ emptyParameters: [" <searchAttributes>", " <searchElements>", " [root]", " [ignoreCase]"],
+ status: "ERROR"
+ });
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "pagemod remove attribute foo bar",
+ emptyParameters: [" [root]", " [ignoreCase]"],
+ status: "VALID"
+ });
+
+ DeveloperToolbarTest.exec({
+ typed: "pagemod remove attribute foo bar",
+ outputMatch: /^[^:]+: 0\. [^:]+: 0\.\s*$/
+ });
+
+ is(getContent(), initialHtml, "nothing changed in the page");
+
+ DeveloperToolbarTest.exec({
+ typed: "pagemod remove attribute foo p",
+ outputMatch: /^[^:]+: 3\. [^:]+: 0\.\s*$/
+ });
+
+ is(getContent(), initialHtml, "nothing changed in the page");
+
+ DeveloperToolbarTest.exec({
+ typed: "pagemod remove attribute id p,span",
+ outputMatch: /^[^:]+: 5\. [^:]+: 1\.\s*$/
+ });
+
+ is(getContent().indexOf('<p id="someid">#someid'), -1,
+ "p#someid attribute removed");
+ isnot(getContent().indexOf("<p>#someid"), -1,
+ "p with someid content still exists");
+
+ resetContent();
+
+ DeveloperToolbarTest.exec({
+ typed: "pagemod remove attribute Class p",
+ outputMatch: /^[^:]+: 3\. [^:]+: 0\.\s*$/
+ });
+
+ is(getContent(), initialHtml, "nothing changed in the page");
+
+ DeveloperToolbarTest.exec({
+ typed: "pagemod remove attribute Class p --ignoreCase",
+ outputMatch: /^[^:]+: 3\. [^:]+: 1\.\s*$/
+ });
+
+ is(getContent().indexOf('<p class="someclass">.someclass'), -1,
+ "p.someclass attribute removed");
+ isnot(getContent().indexOf("<p>.someclass"), -1,
+ "p with someclass content still exists");
+
+ resetContent();
+ }
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_responsivemode.js
@@ -0,0 +1,58 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+ DeveloperToolbarTest.test("about:blank", function GAT_test() {
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "resize toggle",
+ status: "VALID"
+ });
+ DeveloperToolbarTest.exec();
+ ok(isOpen(), "responsive mode is open");
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "resize toggle",
+ status: "VALID"
+ });
+ DeveloperToolbarTest.exec();
+ ok(isClosed(), "responsive mode is closed");
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "resize on",
+ status: "VALID"
+ });
+ DeveloperToolbarTest.exec();
+ ok(isOpen(), "responsive mode is open");
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "resize off",
+ status: "VALID"
+ });
+ DeveloperToolbarTest.exec();
+ ok(isClosed(), "responsive mode is closed");
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "resize to 400 400",
+ status: "VALID"
+ });
+ DeveloperToolbarTest.exec();
+ ok(isOpen(), "responsive mode is open");
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "resize off",
+ status: "VALID"
+ });
+ DeveloperToolbarTest.exec();
+ ok(isClosed(), "responsive mode is closed");
+
+ executeSoon(finish);
+ });
+
+ function isOpen() {
+ return !!gBrowser.selectedTab.__responsiveUI;
+ }
+
+ function isClosed() {
+ return !isOpen();
+ }
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_restart.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that restart command works properly (input wise)
+
+const TEST_URI = "data:text/html;charset=utf-8,gcli-command-restart";
+
+function test() {
+ DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+ testRestart();
+ finish();
+ });
+}
+
+function testRestart() {
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "restart",
+ markup: "VVVVVVV",
+ status: "VALID",
+ emptyParameters: [ " [nocache]" ],
+ });
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "restart ",
+ markup: "VVVVVVVV",
+ status: "VALID",
+ directTabText: "false"
+ });
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "restart t",
+ markup: "VVVVVVVVI",
+ status: "ERROR",
+ directTabText: "rue"
+ });
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "restart --nocache",
+ markup: "VVVVVVVVVVVVVVVVV",
+ status: "VALID"
+ });
+
+ DeveloperToolbarTest.checkInputStatus({
+ typed: "restart --noca",
+ markup: "VVVVVVVVEEEEEE",
+ status: "ERROR",
+ });
+}
--- a/browser/devtools/commandline/test/browser_gcli_web.js
+++ b/browser/devtools/commandline/test/browser_gcli_web.js
@@ -1058,54 +1058,54 @@ exports.check = function(checks) {
if (paramName === 'command') {
assignment = requisition.commandAssignment;
}
else {
assignment = requisition.getAssignment(paramName);
}
if (assignment == null) {
- test.ok(false, 'Unknown parameter: ' + paramName);
+ test.ok(false, 'Unknown arg: ' + paramName);
return;
}
if (check.value) {
test.is(assignment.value,
check.value,
- 'checkStatus value for ' + paramName);
+ 'arg[\'' + paramName + '\'].value');
}
if (check.name) {
test.is(assignment.value.name,
check.name,
- 'checkStatus name for ' + paramName);
+ 'arg[\'' + paramName + '\'].name');
}
if (check.type) {
test.is(assignment.arg.type,
check.type,
- 'checkStatus type for ' + paramName);
+ 'arg[\'' + paramName + '\'].type');
}
if (check.arg) {
test.is(assignment.arg.toString(),
check.arg,
- 'checkStatus arg for ' + paramName);
+ 'arg[\'' + paramName + '\'].arg');
}
if (check.status) {
test.is(assignment.getStatus().toString(),
check.status,
- 'checkStatus status for ' + paramName);
+ 'arg[\'' + paramName + '\'].status');
}
if (check.message) {
test.is(assignment.getMessage(),
check.message,
- 'checkStatus message for ' + paramName);
+ 'arg[\'' + paramName + '\'].message');
}
});
}
};
/**
* Execute a command:
*
@@ -1728,16 +1728,17 @@ exports.setup = function() {
canon.addCommand(exports.tsnExtend);
canon.addCommand(exports.tsnDeep);
canon.addCommand(exports.tsnDeepDown);
canon.addCommand(exports.tsnDeepDownNested);
canon.addCommand(exports.tsnDeepDownNestedCmd);
canon.addCommand(exports.tselarr);
canon.addCommand(exports.tsm);
canon.addCommand(exports.tsg);
+ canon.addCommand(exports.tscook);
};
exports.shutdown = function() {
canon.removeCommand(exports.tsv);
canon.removeCommand(exports.tsr);
canon.removeCommand(exports.tse);
canon.removeCommand(exports.tsj);
canon.removeCommand(exports.tsb);
@@ -1751,16 +1752,17 @@ exports.shutdown = function() {
canon.removeCommand(exports.tsnExtend);
canon.removeCommand(exports.tsnDeep);
canon.removeCommand(exports.tsnDeepDown);
canon.removeCommand(exports.tsnDeepDownNested);
canon.removeCommand(exports.tsnDeepDownNestedCmd);
canon.removeCommand(exports.tselarr);
canon.removeCommand(exports.tsm);
canon.removeCommand(exports.tsg);
+ canon.removeCommand(exports.tscook);
types.deregisterType(exports.optionType);
types.deregisterType(exports.optionValue);
};
exports.option1 = { type: types.getType('string') };
exports.option2 = { type: types.getType('number') };
@@ -1970,16 +1972,56 @@ exports.tsg = {
description: 'num param'
}
]
}
],
exec: createExec('tsg')
};
+exports.tscook = {
+ name: 'tscook',
+ description: 'param group test to catch problems with cookie command',
+ params: [
+ {
+ name: 'key',
+ type: 'string',
+ description: 'tscookKeyDesc'
+ },
+ {
+ name: 'value',
+ type: 'string',
+ description: 'tscookValueDesc'
+ },
+ {
+ group: 'tscookOptionsDesc',
+ params: [
+ {
+ name: 'path',
+ type: 'string',
+ defaultValue: '/',
+ description: 'tscookPathDesc'
+ },
+ {
+ name: 'domain',
+ type: 'string',
+ defaultValue: null,
+ description: 'tscookDomainDesc'
+ },
+ {
+ name: 'secure',
+ type: 'boolean',
+ description: 'tscookSecureDesc'
+ }
+ ]
+ }
+ ],
+ exec: createExec('tscook')
+};
+
});
/*
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -2880,16 +2922,50 @@ exports.testCompleted = function(options
solo: { value: undefined, status: 'INCOMPLETE' },
txt1: { value: 'fred', status: 'VALID' },
bool: { value: undefined, status: 'VALID' },
txt2: { value: undefined, status: 'VALID' },
num: { value: undefined, status: 'VALID' }
}
});
+ helpers.setInput('tscook key value --path path --');
+ helpers.check({
+ input: 'tscook key value --path path --',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVII',
+ directTabText: 'domain',
+ arrowTabText: '',
+ status: 'ERROR',
+ emptyParameters: [ ],
+ args: {
+ key: { value: 'key', status: 'VALID' },
+ value: { value: 'value', status: 'VALID' },
+ path: { value: 'path', status: 'VALID' },
+ domain: { value: undefined, status: 'VALID' },
+ secure: { value: false, status: 'VALID' }
+ }
+ });
+
+ helpers.setInput('tscook key value --path path --domain domain --');
+ helpers.check({
+ input: 'tscook key value --path path --domain domain --',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVII',
+ directTabText: 'secure',
+ arrowTabText: '',
+ status: 'ERROR',
+ emptyParameters: [ ],
+ args: {
+ key: { value: 'key', status: 'VALID' },
+ value: { value: 'value', status: 'VALID' },
+ path: { value: 'path', status: 'VALID' },
+ domain: { value: 'domain', status: 'VALID' },
+ secure: { value: false, status: 'VALID' }
+ }
+ });
+
// Expand out to christmas tree command line
};
exports.testIncomplete = function(options) {
var requisition = options.display.requisition;
helpers.setInput('tsm a a -');
helpers.check({
--- a/browser/devtools/responsivedesign/responsivedesign.jsm
+++ b/browser/devtools/responsivedesign/responsivedesign.jsm
@@ -29,16 +29,48 @@ let ResponsiveUIManager = {
*/
toggle: function(aWindow, aTab) {
if (aTab.__responsiveUI) {
aTab.__responsiveUI.close();
} else {
aTab.__responsiveUI = new ResponsiveUI(aWindow, aTab);
}
},
+
+ /**
+ * Handle gcli commands.
+ *
+ * @param aWindow the browser window.
+ * @param aTab the tab targeted.
+ * @param aCommand the command name.
+ * @param aArgs command arguments.
+ */
+ handleGcliCommand: function(aWindow, aTab, aCommand, aArgs) {
+ switch (aCommand) {
+ case "resize to":
+ if (!aTab.__responsiveUI) {
+ aTab.__responsiveUI = new ResponsiveUI(aWindow, aTab);
+ }
+ aTab.__responsiveUI.setSize(aArgs.width, aArgs.height);
+ break;
+ case "resize on":
+ if (!aTab.__responsiveUI) {
+ aTab.__responsiveUI = new ResponsiveUI(aWindow, aTab);
+ }
+ break;
+ case "resize off":
+ if (aTab.__responsiveUI) {
+ aTab.__responsiveUI.close();
+ }
+ break;
+ case "resize toggle":
+ this.toggle(aWindow, aTab);
+ default:
+ }
+ },
}
let presets = [
// Phones
{key: "320x480", width: 320, height: 480}, // iPhone, B2G, with <meta viewport>
{key: "360x640", width: 360, height: 640}, // Android 4, phones, with <meta viewport>
// Tablets
@@ -371,18 +403,18 @@ ResponsiveUI.prototype = {
/**
* Change the size of the browser.
*
* @param aWidth width of the browser.
* @param aHeight height of the browser.
*/
setSize: function RUI_setSize(aWidth, aHeight) {
- this.currentWidth = aWidth;
- this.currentHeight = aHeight;
+ this.currentWidth = Math.min(Math.max(aWidth, MIN_WIDTH), MAX_WIDTH);
+ this.currentHeight = Math.min(Math.max(aHeight, MIN_HEIGHT), MAX_WIDTH);
// We resize the containing stack.
let style = "max-width: %width;" +
"min-width: %width;" +
"max-height: %height;" +
"min-height: %height;";
style = style.replace(/%width/g, this.currentWidth + "px");
--- a/browser/devtools/shared/DeveloperToolbar.jsm
+++ b/browser/devtools/shared/DeveloperToolbar.jsm
@@ -106,16 +106,29 @@ DeveloperToolbar.prototype.toggle = func
if (this.visible) {
this.hide();
} else {
this.show(true);
}
};
/**
+ * Called from browser.xul in response to menu-click or keyboard shortcut to
+ * toggle the toolbar
+ */
+DeveloperToolbar.prototype.focus = function DT_focus()
+{
+ if (this.visible) {
+ this._input.focus();
+ } else {
+ this.show(true);
+ }
+};
+
+/**
* Even if the user has not clicked on 'Got it' in the intro, we only show it
* once per session.
* Warning this is slightly messed up because this.DeveloperToolbar is not the
* same as this.DeveloperToolbar when in browser.js context.
*/
DeveloperToolbar.introShownThisSession = false;
/**
--- a/browser/devtools/styleeditor/StyleEditor.jsm
+++ b/browser/devtools/styleeditor/StyleEditor.jsm
@@ -31,20 +31,20 @@ const UPDATE_STYLESHEET_THROTTLE_DELAY =
const STYLESHEET_EXPANDO = "-moz-styleeditor-stylesheet-";
const TRANSITIONS_PREF = "devtools.styleeditor.transitions";
const TRANSITION_CLASS = "moz-styleeditor-transitioning";
const TRANSITION_DURATION_MS = 500;
const TRANSITION_RULE = "\
:root.moz-styleeditor-transitioning, :root.moz-styleeditor-transitioning * {\
--moz-transition-duration: " + TRANSITION_DURATION_MS + "ms !important; \
--moz-transition-delay: 0ms !important;\
--moz-transition-timing-function: ease-out !important;\
--moz-transition-property: all !important;\
+transition-duration: " + TRANSITION_DURATION_MS + "ms !important; \
+transition-delay: 0ms !important;\
+transition-timing-function: ease-out !important;\
+transition-property: all !important;\
}";
/**
* Style Editor module-global preferences
*/
const TRANSITIONS_ENABLED = Services.prefs.getBoolPref(TRANSITIONS_PREF);
--- a/browser/devtools/webconsole/HUDService-content.js
+++ b/browser/devtools/webconsole/HUDService-content.js
@@ -284,17 +284,18 @@ let Manager = {
ConsoleListener.init(aMessage);
break;
case "NetworkMonitor":
NetworkMonitor.init(aMessage);
break;
case "LocationChange":
ConsoleProgressListener.startMonitor(ConsoleProgressListener
.MONITOR_LOCATION_CHANGE);
- ConsoleProgressListener.sendLocation();
+ ConsoleProgressListener.sendLocation(this.window.location.href,
+ this.window.document.title);
break;
default:
Cu.reportError("Web Console content: unknown feature " + aFeature);
break;
}
this._enabledFeatures.push(aFeature);
},
@@ -2220,17 +2221,17 @@ let NetworkMonitor = {
let entry = aHttpActivity.log.entries[0];
let harTimings = entry.timings;
// Not clear how we can determine "blocked" time.
harTimings.blocked = -1;
// DNS timing information is available only in when the DNS record is not
// cached.
- harTimings.dns = timings.STATUS_RESOLVING ?
+ harTimings.dns = timings.STATUS_RESOLVING && timings.STATUS_RESOLVED ?
timings.STATUS_RESOLVED.last -
timings.STATUS_RESOLVING.first : -1;
if (timings.STATUS_CONNECTING_TO && timings.STATUS_CONNECTED_TO) {
harTimings.connect = timings.STATUS_CONNECTED_TO.last -
timings.STATUS_CONNECTING_TO.first;
}
else if (timings.STATUS_SENDING_TO) {
@@ -2466,44 +2467,56 @@ let ConsoleProgressListener = {
* Check if the current window.top location is changing, given the arguments
* of nsIWebProgressListener.onStateChange. If that is the case, the remote
* Web Console instance is notified.
* @private
*/
_checkLocationChange:
function CPL__checkLocationChange(aProgress, aRequest, aState, aStatus)
{
+ let isStart = aState & Ci.nsIWebProgressListener.STATE_START;
let isStop = aState & Ci.nsIWebProgressListener.STATE_STOP;
let isNetwork = aState & Ci.nsIWebProgressListener.STATE_IS_NETWORK;
let isWindow = aState & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
// Skip non-interesting states.
- if (!isStop || !isNetwork || !isWindow ||
+ if (!isNetwork || !isWindow ||
aProgress.DOMWindow != Manager.window) {
return;
}
- this.sendLocation();
+ if (isStart && aRequest instanceof Ci.nsIChannel) {
+ this.sendLocation(aRequest.URI.spec, "");
+ }
+ else if (isStop) {
+ this.sendLocation(Manager.window.location.href,
+ Manager.window.document.title);
+ }
},
onLocationChange: function() {},
onStatusChange: function() {},
onProgressChange: function() {},
onSecurityChange: function() {},
/**
* Send the location of the current top window to the remote Web Console.
* A "WebConsole:LocationChange" message is sent. The JSON object holds two
* properties: location and title.
+ *
+ * @param string aLocation
+ * Current page address.
+ * @param string aTitle
+ * Current page title.
*/
- sendLocation: function CPL_sendLocation()
+ sendLocation: function CPL_sendLocation(aLocation, aTitle)
{
let message = {
- "location": Manager.window.location.href,
- "title": Manager.window.document.title,
+ "location": aLocation,
+ "title": aTitle,
};
Manager.sendMessage("WebConsole:LocationChange", message);
},
/**
* Destroy the ConsoleProgressListener.
*/
destroy: function CPL_destroy()
--- a/browser/devtools/webconsole/HUDService.jsm
+++ b/browser/devtools/webconsole/HUDService.jsm
@@ -5,16 +5,18 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const CONSOLEAPI_CLASS_ID = "{b49c18f8-3379-4fc0-8c90-d7772c1a9ff3}";
+const MIXED_CONTENT_LEARN_MORE = "https://developer.mozilla.org/en/Security/MixedContent";
+
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
var EXPORTED_SYMBOLS = ["HUDService", "ConsoleUtils"];
XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
"@mozilla.org/widget/clipboardhelper;1",
"nsIClipboardHelper");
@@ -2145,28 +2147,36 @@ HeadsUpDisplay.prototype = {
urlNode.setAttribute("flex", "1");
urlNode.setAttribute("title", request.url);
urlNode.setAttribute("value", request.url);
urlNode.classList.add("hud-clickable");
urlNode.classList.add("webconsole-msg-body-piece");
urlNode.classList.add("webconsole-msg-url");
linkNode.appendChild(urlNode);
+ let severity = SEVERITY_LOG;
+ if(this.isMixedContentLoad(request.url, this.contentLocation)) {
+ urlNode.classList.add("webconsole-mixed-content");
+ this.makeMixedContentNode(linkNode);
+ //If we define a SEVERITY_SECURITY in the future, switch this to SEVERITY_SECURITY
+ severity = SEVERITY_WARNING;
+ }
+
let statusNode = this.chromeDocument.createElementNS(XUL_NS, "label");
statusNode.setAttribute("value", "");
statusNode.classList.add("hud-clickable");
statusNode.classList.add("webconsole-msg-body-piece");
statusNode.classList.add("webconsole-msg-status");
linkNode.appendChild(statusNode);
let clipboardText = request.method + " " + request.url;
let messageNode = ConsoleUtils.createMessageNode(this.chromeDocument,
CATEGORY_NETWORK,
- SEVERITY_LOG,
+ severity,
msgNode,
this.hudId,
null,
null,
clipboardText);
messageNode._connectionId = entry.connection;
@@ -2946,16 +2956,63 @@ HeadsUpDisplay.prototype = {
this.positionMenuitems.below.removeEventListener("command",
this._positionConsoleBelow, false);
this.positionMenuitems.window.removeEventListener("command",
this._positionConsoleWindow, false);
this.closeButton.removeEventListener("command",
this.closeButtonOnCommand, false);
},
+
+ /**
+ * Determine whether the request should display a Mixed Content warning
+ *
+ * @param string request
+ * location of the requested content
+ * @param string contentLocation
+ * location of the current page
+ * @return bool
+ * True if the content is mixed, false if not
+ */
+ isMixedContentLoad: function HUD_isMixedContentLoad(request, contentLocation) {
+ try {
+ let requestURIObject = Services.io.newURI(request, null, null);
+ let contentWindowURI = Services.io.newURI(contentLocation, null, null);
+ return (contentWindowURI.scheme == "https" && requestURIObject.scheme != "https");
+ } catch(e) {
+ return false;
+ }
+ },
+
+ /**
+ * Create a mixedContentWarningNode and add it the webconsole output.
+ *
+ * @param linkNode
+ * parent to the requested urlNode
+ */
+ makeMixedContentNode: function HUD_makeMixedContentNode(linkNode) {
+ let mixedContentWarning = "[" + l10n.getStr("webConsoleMixedContentWarning") + "]";
+
+ //mixedContentWarning message links to a Learn More page
+ let mixedContentWarningNode = this.chromeDocument.createElement("label");
+ mixedContentWarningNode.setAttribute("value", mixedContentWarning);
+ mixedContentWarningNode.setAttribute("title", mixedContentWarning);
+
+ //UI for mixed content warning.
+ mixedContentWarningNode.classList.add("hud-clickable");
+ mixedContentWarningNode.classList.add("webconsole-mixed-content-link");
+
+ linkNode.appendChild(mixedContentWarningNode);
+
+ mixedContentWarningNode.addEventListener("click", function(aEvent) {
+ this.chromeWindow.openUILinkIn(MIXED_CONTENT_LEARN_MORE, "tab");
+ aEvent.preventDefault();
+ aEvent.stopPropagation();
+ }.bind(this));
+ },
};
/**
* Creates a DOM Node factory for XUL nodes - as well as textNodes
* @param aFactoryType "xul" or "text"
* @param ignored This parameter is currently ignored, and will be removed
* See bug 594304
* @param aDocument The document, the factory is to generate nodes from
--- a/browser/devtools/webconsole/WebConsoleUtils.jsm
+++ b/browser/devtools/webconsole/WebConsoleUtils.jsm
@@ -241,28 +241,31 @@ var WebConsoleUtils = {
case "regexp":
output = aResult.toString();
break;
case "null":
case "undefined":
output = type;
break;
default:
- if (aResult.toSource) {
- try {
+ try {
+ if (aResult.toSource) {
output = aResult.toSource();
- } catch (ex) { }
+ }
+ if (!output || output == "({})") {
+ output = aResult + "";
+ }
}
- if (!output || output == "({})") {
- output = aResult.toString();
+ catch (ex) {
+ output = ex;
}
break;
}
- return output;
+ return output + "";
},
/**
* Format a string for output.
*
* @param string aString
* The string you want to display.
* @return string
--- a/browser/devtools/webconsole/test/Makefile.in
+++ b/browser/devtools/webconsole/test/Makefile.in
@@ -104,16 +104,18 @@ MOCHITEST_BROWSER_FILES = \
browser_webconsole_bug_664131_console_group.js \
browser_webconsole_bug_704295.js \
browser_webconsole_bug_658368_time_methods.js \
browser_webconsole_bug_622303_persistent_filters.js \
browser_webconsole_window_zombie.js \
browser_cached_messages.js \
browser_bug664688_sandbox_update_after_navigation.js \
browser_webconsole_menustatus.js \
+ browser_result_format_as_string.js \
+ browser_webconsole_bug_737873_mixedcontent.js \
head.js \
$(NULL)
MOCHITEST_BROWSER_FILES += \
test-console.html \
test-network.html \
test-network-request.html \
test-mutation.html \
@@ -176,11 +178,13 @@ MOCHITEST_BROWSER_FILES += \
test-bug-585956-console-trace.html \
test-bug-644419-log-limits.html \
test-bug-632275-getters.html \
test-bug-646025-console-file-location.html \
test-file-location.js \
test-bug-658368-time-methods.html \
test-webconsole-error-observer.html \
test-for-of.html \
+ test-result-format-as-string.html \
+ test-bug-737873-mixedcontent.html \
$(NULL)
include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_result_format_as_string.js
@@ -0,0 +1,49 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Make sure that JS eval result are properly formatted as strings.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-result-format-as-string.html";
+
+function test()
+{
+ waitForExplicitFinish();
+
+ addTab(TEST_URI);
+
+ gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
+ gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
+ openConsole(null, performTest);
+ }, true);
+}
+
+function performTest(hud)
+{
+ hud.jsterm.clearOutput(true);
+
+ hud.jsterm.execute("document.querySelector('p')");
+ waitForSuccess({
+ name: "eval result shown",
+ validatorFn: function()
+ {
+ return hud.outputNode.querySelector(".webconsole-msg-output");
+ },
+ successFn: function()
+ {
+ is(hud.outputNode.textContent.indexOf("bug772506_content"), -1,
+ "no content element found");
+ ok(!hud.outputNode.querySelector("div"), "no div element found");
+
+ let msg = hud.outputNode.querySelector(".webconsole-msg-output");
+ ok(msg, "eval output node found");
+ isnot(msg.textContent.indexOf("HTMLDivElement"), -1,
+ "HTMLDivElement string found");
+ EventUtils.synthesizeMouseAtCenter(msg, {type: "mousemove"});
+ ok(!gBrowser._bug772506, "no content variable");
+
+ finishTest();
+ },
+ failureFn: finishTest,
+ });
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_737873_mixedcontent.js
@@ -0,0 +1,80 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Tanvi Vyas <tanvi@mozilla.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Tests that the Web Console Mixed Content messages are displayed
+
+const TEST_HTTPS_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html";
+
+function test() {
+ addTab("data:text/html,Web Console basic network logging test");
+ browser.addEventListener("load", onLoad, true);
+}
+
+function onLoad(aEvent) {
+ browser.removeEventListener("load", onLoad, true);
+ openConsole(null, testMixedContent);
+}
+
+function testMixedContent(hud) {
+ content.location = TEST_HTTPS_URI;
+ var aOutputNode = hud.outputNode;
+
+ waitForSuccess(
+ {
+ name: "mixed content warning displayed successfully",
+ validatorFn: function() {
+ return ( aOutputNode.querySelector(".webconsole-mixed-content") );
+ },
+
+ successFn: function() {
+
+ //tests on the urlnode
+ let node = aOutputNode.querySelector(".webconsole-mixed-content");
+ ok(testSeverity(node), "Severity type is SEVERITY_WARNING.");
+
+ //tests on the warningNode
+ let warningNode = aOutputNode.querySelector(".webconsole-mixed-content-link");
+ is(warningNode.value, "[Mixed Content]", "Message text is accurate." );
+ testClickOpenNewTab(warningNode);
+
+ finishTest();
+ },
+
+ failureFn: finishTest,
+ }
+ );
+
+}
+
+function testSeverity(node) {
+ let linkNode = node.parentNode;
+ let msgNode = linkNode.parentNode;
+ let bodyNode = msgNode.parentNode;
+ let finalNode = bodyNode.parentNode;
+
+ return finalNode.classList.contains("webconsole-msg-warn");
+}
+
+function testClickOpenNewTab(warningNode) {
+ /* Invoke the click event and check if a new tab would open to the correct page */
+ let linkOpened = false;
+ let oldOpenUILinkIn = window.openUILinkIn;
+
+ window.openUILinkIn = function(aLink) {
+ if (aLink == "https://developer.mozilla.org/en/Security/MixedContent");
+ linkOpened = true;
+ }
+
+ EventUtils.synthesizeMouse(warningNode, 2, 2, {});
+
+ ok(linkOpened, "Clicking the Mixed Content Warning node opens the desired page");
+
+ window.openUILinkIn = oldOpenUILinkIn;
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
+ <title>Mixed Content test - http on https</title>
+ <script src="testscript.js"></script>
+ <!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+ </head>
+ <body>
+ <iframe src = "http://example.com"></iframe>
+ </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-result-format-as-string.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test: jsterm eval format as a string</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>Make sure js eval results are formatted as strings.</p>
+ <script>
+ document.querySelector("p").toSource = function() {
+ var element = document.createElement("div");
+ element.textContent = "bug772506_content";
+ element.setAttribute("onmousemove",
+ "(function () {" +
+ " gBrowser._bug772506 = 'foobar';" +
+ "})();"
+ );
+ return element;
+ };
+ </script>
+ </body>
+</html>
--- a/browser/installer/Makefile.in
+++ b/browser/installer/Makefile.in
@@ -61,18 +61,18 @@ DEFINES += -D_MSC_VER=$(_MSC_VER)
endif
ifeq ($(MOZ_CHROME_FILE_FORMAT),jar)
DEFINES += -DJAREXT=.jar
else
DEFINES += -DJAREXT=
endif
-ifdef MOZ_ANGLE
-DEFINES += -DMOZ_ANGLE=$(MOZ_ANGLE)
+ifdef MOZ_ANGLE_RENDERER
+DEFINES += -DMOZ_ANGLE_RENDERER=$(MOZ_ANGLE_RENDERER)
DEFINES += -DMOZ_D3DX9_DLL=$(MOZ_D3DX9_DLL)
DEFINES += -DMOZ_D3DCOMPILER_DLL=$(MOZ_D3DCOMPILER_DLL)
endif
include $(topsrcdir)/ipc/app/defs.mk
DEFINES += -DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME)
# Set MSVC dlls version to package, if any.
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -90,16 +90,19 @@
@BINPATH@/msvcp90.dll
@BINPATH@/msvcr90.dll
#elif MOZ_MSVC_REDIST == 1600
@BINPATH@/msvcp100.dll
@BINPATH@/msvcr100.dll
#elif MOZ_MSVC_REDIST == 1700
@BINPATH@/msvcp110.dll
@BINPATH@/msvcr110.dll
+#ifdef MOZ_METRO
+@BINPATH@/vccorlib110.dll
+#endif
#endif
#endif
#endif
[browser]
; [Base Browser Files]
#ifndef XP_UNIX
@BINPATH@/@MOZ_APP_NAME@.exe
@@ -466,16 +469,19 @@
@BINPATH@/components/messageWakeupService.js
@BINPATH@/components/messageWakeupService.manifest
@BINPATH@/components/SettingsManager.js
@BINPATH@/components/SettingsManager.manifest
@BINPATH@/components/Webapps.js
@BINPATH@/components/Webapps.manifest
@BINPATH@/components/AppsService.js
@BINPATH@/components/AppsService.manifest
+@BINPATH@/components/nsDOMIdentity.js
+@BINPATH@/components/nsIDService.js
+@BINPATH@/components/Identity.manifest
@BINPATH@/components/ContactManager.js
@BINPATH@/components/ContactManager.manifest
@BINPATH@/components/AlarmsManager.js
@BINPATH@/components/AlarmsManager.manifest
#ifdef ENABLE_MARIONETTE
@BINPATH@/chrome/marionette@JAREXT@
@BINPATH@/chrome/marionette.manifest
@@ -500,17 +506,17 @@
#endif
; GNOME hooks
#ifdef MOZ_ENABLE_GNOME_COMPONENT
@BINPATH@/components/@DLL_PREFIX@mozgnome@DLL_SUFFIX@
#endif
; ANGLE GLES-on-D3D rendering library
-#ifdef MOZ_ANGLE
+#ifdef MOZ_ANGLE_RENDERER
@BINPATH@/libEGL.dll
@BINPATH@/libGLESv2.dll
@BINPATH@/@MOZ_D3DX9_DLL@
@BINPATH@/@MOZ_D3DCOMPILER_DLL@
#endif
; [Browser Chrome Files]
@BINPATH@/chrome/browser@JAREXT@
@@ -689,16 +695,18 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DL
#ifdef XP_WIN
@BINPATH@/webapp-uninstaller@BIN_SUFFIX@
#endif
@BINPATH@/webapprt-stub@BIN_SUFFIX@
@BINPATH@/webapprt/webapprt.ini
@BINPATH@/webapprt/chrome.manifest
@BINPATH@/webapprt/chrome/webapprt@JAREXT@
@BINPATH@/webapprt/chrome/webapprt.manifest
+@BINPATH@/webapprt/chrome/@AB_CD@@JAREXT@
+@BINPATH@/webapprt/chrome/@AB_CD@.manifest
@BINPATH@/webapprt/components/CommandLineHandler.js
@BINPATH@/webapprt/components/ContentPermission.js
@BINPATH@/webapprt/components/ContentPolicy.js
@BINPATH@/webapprt/components/DirectoryProvider.js
@BINPATH@/webapprt/components/components.manifest
@BINPATH@/webapprt/defaults/preferences/prefs.js
@BINPATH@/webapprt/modules/WebappRT.jsm
@BINPATH@/webapprt/modules/WebappsHandler.jsm
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -1383,16 +1383,19 @@ xpicleanup@BIN_SUFFIX@
#endif
#if MOZ_MSVC_REDIST != 1600
msvcp100.dll
msvcr100.dll
#endif
#if MOZ_MSVC_REDIST != 1700
msvcp110.dll
msvcr110.dll
+ #ifdef MOZ_METRO
+ vccorlib110.dll
+ #endif
#endif
plugins/npnul32.dll
#endif
@DLL_PREFIX@xpcom_core@DLL_SUFFIX@
components/@DLL_PREFIX@jar50@DLL_SUFFIX@
#ifdef XP_WIN
components/xpinstal.dll
#else
--- a/browser/installer/windows/nsis/installer.nsi
+++ b/browser/installer/windows/nsis/installer.nsi
@@ -369,17 +369,17 @@ Section "-Application" APP_IDX
${EndIf}
${EndIf}
${If} $InstallMaintenanceService == "1"
; The user wants to install the maintenance service, so execute
; the pre-packaged maintenance service installer.
; This option can only be turned on if the user is an admin so there
; is no need to use ExecShell w/ verb runas to enforce elevated.
- nsExec::Exec "$INSTDIR\maintenanceservice_installer.exe"
+ nsExec::Exec "$\"$INSTDIR\maintenanceservice_installer.exe$\""
${EndIf}
!endif
; These need special handling on uninstall since they may be overwritten by
; an install into a different location.
StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\App Paths\${FileMainEXE}"
${WriteRegStr2} $TmpVal "$0" "" "$INSTDIR\${FileMainEXE}" 0
${WriteRegStr2} $TmpVal "$0" "Path" "$INSTDIR" 0
@@ -692,17 +692,17 @@ Function CheckExistingInstall
FunctionEnd
Function LaunchApp
ClearErrors
${GetParameters} $0
${GetOptions} "$0" "/UAC:" $1
${If} ${Errors}
${ManualCloseAppPrompt} "${WindowClass}" "$(WARN_MANUALLY_CLOSE_APP_LAUNCH)"
- Exec "$INSTDIR\${FileMainEXE}"
+ Exec "$\"$INSTDIR\${FileMainEXE}$\""
${Else}
GetFunctionAddress $0 LaunchAppFromElevatedProcess
UAC::ExecCodeSegment $0
${EndIf}
FunctionEnd
Function LaunchAppFromElevatedProcess
${ManualCloseAppPrompt} "${WindowClass}" "$(WARN_MANUALLY_CLOSE_APP_LAUNCH)"
@@ -711,17 +711,17 @@ Function LaunchAppFromElevatedProcess
; from an elevated installer since $INSTDIR will not be set in this installer
${StrFilter} "${FileMainEXE}" "+" "" "" $R9
ReadRegStr $0 HKLM "Software\Clients\StartMenuInternet\$R9\DefaultIcon" ""
${GetPathFromString} "$0" $0
${GetParent} "$0" $1
; Set our current working directory to the application's install directory
; otherwise the 7-Zip temp directory will be in use and won't be deleted.
SetOutPath "$1"
- Exec "$0"
+ Exec "$\"$0$\""
FunctionEnd
################################################################################
# Language
!insertmacro MOZ_MUI_LANGUAGE 'baseLocale'
!verbose push
!verbose 3
--- a/browser/installer/windows/nsis/shared.nsh
+++ b/browser/installer/windows/nsis/shared.nsh
@@ -109,17 +109,17 @@
; and we need a return result back to the service when run that way.
${If} $5 == ""
; An install of maintenance service was never attempted.
; We know we are an Admin and that we have write access into HKLM
; based on the above checks, so attempt to just run the EXE.
; In the worst case, in case there is some edge case with the
; IsAdmin check and the permissions check, the maintenance service
; will just fail to be attempted to be installed.
- nsExec::Exec "$INSTDIR\maintenanceservice_installer.exe"
+ nsExec::Exec "$\"$INSTDIR\maintenanceservice_installer.exe$\""
${EndIf}
${EndIf}
!endif
!macroend
!define PostUpdate "!insertmacro PostUpdate"
!macro SetAsDefaultAppGlobal
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -174,22 +174,25 @@ repackage-win32-installer-%:
else
repackage-win32-installer-%: ;
endif
clobber-zip:
$(RM) $(STAGEDIST)/chrome/$(AB_CD).jar \
$(STAGEDIST)/chrome/$(AB_CD).manifest \
+ $(STAGEDIST)/webapprt/chrome/$(AB_CD).jar \
+ $(STAGEDIST)/webapprt/chrome/$(AB_CD).manifest \
$(STAGEDIST)/$(PREF_DIR)/firefox-l10n.js
$(RM) -rf $(STAGEDIST)/searchplugins \
$(STAGEDIST)/dictionaries \
$(STAGEDIST)/hyphenation \
$(STAGEDIST)/defaults/profile \
- $(STAGEDIST)/chrome/$(AB_CD)
+ $(STAGEDIST)/chrome/$(AB_CD) \
+ $(STAGEDIST)/webapprt/chrome/$(AB_CD)
langpack: langpack-$(AB_CD)
# This is a generic target that will make a langpack, repack ZIP (+tarball)
# builds, and repack an installer if applicable. It is called from the
# tinderbox scripts. Alter it with caution.
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -232,16 +232,19 @@ These should match what Safari and other
<!ENTITY scratchpad.accesskey "s">
<!ENTITY scratchpad.keycode "VK_F4">
<!ENTITY scratchpad.keytext "F4">
<!ENTITY inspectCloseButton.tooltiptext "Close Inspector">
<!ENTITY devToolbarCloseButton.tooltiptext "Close Developer Toolbar">
<!ENTITY devToolbarMenu.label "Developer Toolbar">
+<!ENTITY devToolbarMenu.accesskey "v">
+<!ENTITY devToolbar.keycode "VK_F2">
+<!ENTITY devToolbar.keytext "F2">
<!ENTITY webConsoleButton.label "Web Console">
<!ENTITY inspectorButton.label "Inspector">
<!ENTITY inspectorHTMLCopyInner.label "Copy Inner HTML">
<!ENTITY inspectorHTMLCopyInner.accesskey "I">
<!ENTITY inspectorHTMLCopyOuter.label "Copy Outer HTML">
--- a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
@@ -75,16 +75,34 @@ screenshotDelayManual=The time to wait (
# a dialog when the user is using this command.
screenshotFullPageDesc=Entire webpage? (true/false)
# LOCALIZATION NOTE (screenshotFullscreenManual) A fuller description of the
# 'fullscreen' parameter to the 'screenshot' command, displayed when the user
# asks for help on what it does.
screenshotFullPageManual=True if the screenshot should also include parts of the webpage which are outside the current scrolled bounds.
+# LOCALIZATION NOTE (restartFirefoxDesc) A very short description of the
+# 'restart' command. This string is designed to be shown in a menu alongside the
+# command name, which is why it should be as short as possible.
+restartFirefoxDesc=Restart Firefox
+
+# LOCALIZATION NOTE (restartFirefoxNocacheDesc) A very short string to
+# describe the 'nocache' parameter to the 'restart' command, which is
+# displayed in a dialog when the user is using this command.
+restartFirefoxNocacheDesc=Disables loading content from cache upon restart
+
+# LOCALIZATION NOTE (restartFirefoxRequestCancelled) A string dispalyed to the
+# user when a scheduled restart has been aborted by the user.
+restartFirefoxRequestCancelled=Restart request cancelled by user.
+
+# LOCALIZATION NOTE (restartFirefoxRestarting) A string dispalyed to the
+# user when a restart has been initiated without a delay.
+restartFirefoxRestarting=Restarting Firefox...
+
# LOCALIZATION NOTE (inspectDesc) A very short description of the 'inspect'
# command. See inspectManual for a fuller description of what it does. This
# string is designed to be shown in a menu alongside the command name, which
# is why it should be as short as possible.
inspectDesc=Inspect a node
# LOCALIZATION NOTE (inspectManual) A fuller description of the 'inspect'
# command, displayed when the user asks for help on what it does.
@@ -328,17 +346,348 @@ editManual2=Edit one of the resources th
# when the user is using this command.
editResourceDesc=URL to edit
# LOCALIZATION NOTE (editLineToJumpToDesc) A very short string to describe the
# 'line' parameter to the 'edit' command, which is displayed in a dialog
# when the user is using this command.
editLineToJumpToDesc=Line to jump to
+# LOCALIZATION NOTE (resizePageDesc) A very short string to describe the
+# 'resizepage' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizePageDesc=Resize the page
+
+# LOCALIZATION NOTE (resizePageArgWidthDesc) A very short string to describe the
+# 'width' parameter to the 'resizepage' command, which is displayed in a dialog
+# when the user is using this command.
+resizePageArgWidthDesc=Width in pixels
+
+# LOCALIZATION NOTE (resizePageArgWidthDesc) A very short string to describe the
+# 'height' parameter to the 'resizepage' command, which is displayed in a dialog
+# when the user is using this command.
+resizePageArgHeightDesc=Height in pixels
+
+# LOCALIZATION NOTE (resizeModeOnDesc) A very short string to describe the
+# 'resizeon ' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizeModeOnDesc=Enter Responsive Design Mode
+
+# LOCALIZATION NOTE (resizeModeOffDesc) A very short string to describe the
+# 'resize off' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizeModeOffDesc=Exit Responsive Design Mode
+
+# LOCALIZATION NOTE (resizeModeToggleDesc) A very short string to describe the
+# 'resize toggle' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizeModeToggleDesc=Toggle Responsive Design Mode
+
+# LOCALIZATION NOTE (resizeModeToDesc) A very short string to describe the
+# 'resize to' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizeModeToDesc=Alter page size
+
+# LOCALIZATION NOTE (resizeModeDesc) A very short string to describe the
+# 'resize' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizeModeDesc=Control Responsive Design Mode
+
+# LOCALIZATION NOTE (resizeModeManual) A fuller description of the 'resize'
+# command, displayed when the user asks for help on what it does.
+resizeModeManual=Responsive websites respond to their environment, so they look good on a mobile display, a cinema display and everything in-between. Responsive Design Mode allows you to easily test a variety of page sizes in Firefox without needing to resize your whole browser.
+
# LOCALIZATION NOTE (cmdDesc) A very short description of the 'cmd'
# command. This string is designed to be shown in a menu alongside the command
# name, which is why it should be as short as possible.
cmdDesc=Manipulate the commands
# LOCALIZATION NOTE (cmdRefreshDesc) A very short description of the 'cmd refresh'
# command. This string is designed to be shown in a menu alongside the command
# name, which is why it should be as short as possible.
cmdRefreshDesc=Re-read mozcmd directory
+
+# LOCALIZATION NOTE (addonDesc) A very short description of the 'addon'
+# command. This string is designed to be shown in a menu alongside the command
+# name, which is why it should be as short as possible.
+addonDesc=Manipulate add-ons
+
+# LOCALIZATION NOTE (addonListDesc) A very short description of the 'addon list'
+# command. This string is designed to be shown in a menu alongside the command
+# name, which is why it should be as short as possible.
+addonListDesc=List installed add-ons
+
+# LOCALIZATION NOTE (addonListTypeDesc) A very short description of the
+# 'addon list <type>' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+addonListTypeDesc=Select an addon type
+
+# LOCALIZATION NOTE (addonListDictionaryHeading, addonListExtensionHeading,
+# addonListLocaleHeading, addonListPluginHeading, addonListThemeHeading,
+# addonListUnknownHeading) Used in the output of the 'addon list' command as the
+# first line of output.
+addonListDictionaryHeading=The following dictionaries are currently installed:
+addonListExtensionHeading=The following extensions are currently installed:
+addonListLocaleHeading=The following locales are currently installed:
+addonListPluginHeading=The following plugins are currently installed:
+addonListThemeHeading=The following themes are currently installed:
+addonListAllHeading=The following addons are currently installed:
+addonListUnknownHeading=The following addons of the selected type are currently installed:
+
+# LOCALIZATION NOTE (addonNameDesc) A very short description of the
+# name parameter of numerous addon commands. This string is designed to be shown
+# in a menu alongside the command name, which is why it should be as short as
+# possible.
+addonNameDesc=The name of the add-on
+
+# LOCALIZATION NOTE (addonNoneOfType) Used in the output of the 'addon list'
+# command when a search for addons of a particular type were not found.
+addonNoneOfType=There are no addons of that type installed.
+
+# LOCALIZATION NOTE (addonEnableDesc) A very short description of the
+# 'addon enable <type>' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+addonEnableDesc=Enable the specified add-on
+
+# LOCALIZATION NOTE (addonAlreadyEnabled) Used in the output of the
+# 'addon enable' command when an attempt is made to enable an addon is already
+# enabled.
+addonAlreadyEnabled=%S is already enabled.
+
+# LOCALIZATION NOTE (addonEnabled) Used in the output of the 'addon enable'
+# command when an addon is enabled.
+addonEnabled=%S enabled.
+
+# LOCALIZATION NOTE (addonDisableDesc) A very short description of the
+# 'addon disable <type>' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+addonDisableDesc=Disable the specified add-on
+
+# LOCALIZATION NOTE (addonAlreadyDisabled) Used in the output of the
+# 'addon disable' command when an attempt is made to disable an addon is already
+# disabled.
+addonAlreadyDisabled=%S is already disabled.
+
+# LOCALIZATION NOTE (addonDisabled) Used in the output of the 'addon disable'
+# command when an addon is disabled.
+addonDisabled=%S disabled.
+
+# LOCALIZATION NOTE (exportDesc) A very short description of the 'export'
+# command. This string is designed to be shown in a menu alongside the command
+# name, which is why it should be as short as possible.
+exportDesc=Export resources
+
+# LOCALIZATION NOTE (exportHtmlDesc) A very short description of the 'export
+# html' command. This string is designed to be shown in a menu alongside the
+# command name, which is why it should be as short as possible.
+exportHtmlDesc=Export HTML from page
+
+# LOCALIZATION NOTE (pagemodDesc) A very short description of the 'pagemod'
+# command. This string is designed to be shown in a menu alongside the command
+# name, which is why it should be as short as possible.
+pagemodDesc=Make page changes
+
+# LOCALIZATION NOTE (pagemodReplaceDesc) A very short description of the
+# 'pagemod replace' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+pagemodReplaceDesc=Search and replace in page elements
+
+# LOCALIZATION NOTE (pagemodReplaceSearchDesc) A very short string to describe
+# the 'search' parameter to the 'pagemod replace' command, which is displayed in
+# a dialog when the user is using this command.
+pagemodReplaceSearchDesc=What to search for
+
+# LOCALIZATION NOTE (pagemodReplaceReplaceDesc) A very short string to describe
+# the 'replace' parameter to the 'pagemod replace' command, which is displayed in
+# a dialog when the user is using this command.
+pagemodReplaceReplaceDesc=Replacement string
+
+# LOCALIZATION NOTE (pagemodReplaceIgnoreCaseDesc) A very short string to
+# describe the 'ignoreCase' parameter to the 'pagemod replace' command, which is
+# displayed in a dialog when the user is using this command.
+pagemodReplaceIgnoreCaseDesc=Perform case-insensitive search
+
+# LOCALIZATION NOTE (pagemodReplaceRootDesc) A very short string to describe the
+# 'root' parameter to the 'pagemod replace' command, which is displayed in
+# a dialog when the user is using this command.
+pagemodReplaceRootDesc=CSS selector to root of search
+
+# LOCALIZATION NOTE (pagemodReplaceSelectorDesc) A very short string to describe
+# the 'selector' parameter to the 'pagemod replace' command, which is displayed
+# in a dialog when the user is using this command.
+pagemodReplaceSelectorDesc=CSS selector to match in search
+
+# LOCALIZATION NOTE (pagemodReplaceAttributesDesc) A very short string to
+# describe the 'attributes' parameter to the 'pagemod replace' command, which is
+# displayed in a dialog when the user is using this command.
+pagemodReplaceAttributesDesc=Attribute match regexp
+
+# LOCALIZATION NOTE (pagemodReplaceAttrOnlyDesc) A very short string to describe
+# the 'attrOnly' parameter to the 'pagemod replace' command, which is displayed
+# in a dialog when the user is using this command.
+pagemodReplaceAttrOnlyDesc=Restrict search to attributes
+
+# LOCALIZATION NOTE (pagemodReplaceContentOnlyDesc) A very short string to
+# describe the 'contentOnly' parameter to the 'pagemod replace' command, which
+# is displayed in a dialog when the user is using this command.
+pagemodReplaceContentOnlyDesc=Restrict search to text nodes
+
+# LOCALIZATION NOTE (pagemodReplaceResultMatchedElements) A string displayed as
+# the result of the 'pagemod replace' command.
+pagemodReplaceResult=Elements matched by selector: %1$S. Replaces in text nodes: %2$S. Replaces in attributes: %3$S.
+
+# LOCALIZATION NOTE (pagemodRemoveDesc) A very short description of the
+# 'pagemod remove' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+pagemodRemoveDesc=Remove elements and attributes from page
+
+# LOCALIZATION NOTE (pagemodRemoveElementDesc) A very short description of the
+# 'pagemod remove element' command. This string is designed to be shown in
+# a menu alongside the command name, which is why it should be as short as
+# possible.
+pagemodRemoveElementDesc=Remove elements from page
+
+# LOCALIZATION NOTE (pagemodRemoveElementSearchDesc) A very short string to
+# describe the 'search' parameter to the 'pagemod remove element' command, which
+# is displayed in a dialog when the user is using this command.
+pagemodRemoveElementSearchDesc=CSS selector specifying elements to remove
+
+# LOCALIZATION NOTE (pagemodRemoveElementRootDesc) A very short string to
+# describe the 'root' parameter to the 'pagemod remove element' command, which
+# is displayed in a dialog when the user is using this command.
+pagemodRemoveElementRootDesc=CSS selector specifying root of search
+
+# LOCALIZATION NOTE (pagemodRemoveElementStripOnlyDesc) A very short string to
+# describe the 'stripOnly' parameter to the 'pagemod remove element' command,
+# which is displayed in a dialog when the user is using this command.
+pagemodRemoveElementStripOnlyDesc=Remove element, but leave content
+
+# LOCALIZATION NOTE (pagemodRemoveElementIfEmptyOnlyDesc) A very short string to
+# describe the 'ifEmptyOnly' parameter to the 'pagemod remove element' command,
+# which is displayed in a dialog when the user is using this command.
+pagemodRemoveElementIfEmptyOnlyDesc=Remove only empty elements
+
+# LOCALIZATION NOTE (pagemodRemoveElementResultMatchedAndRemovedElements)
+# A string displayed as the result of the 'pagemod remove element' command.
+pagemodRemoveElementResultMatchedAndRemovedElements=Elements matched by selector: %1$S. Elements removed: %2$S.
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeDesc) A very short description of the
+# 'pagemod remove attribute' command. This string is designed to be shown in
+# a menu alongside the command name, which is why it should be as short as
+# possible.
+pagemodRemoveAttributeDesc=Remove matching atributes
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeSearchAttributesDesc) A very short
+# string to describe the 'searchAttributes' parameter to the 'pagemod remove
+# attribute' command, which is displayed in a dialog when the user is using this
+# command.
+pagemodRemoveAttributeSearchAttributesDesc=Regexp specifying attributes to remove
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeSearchElementsDesc) A very short
+# string to describe the 'searchElements' parameter to the 'pagemod remove
+# attribute' command, which is displayed in a dialog when the user is using this
+# command.
+pagemodRemoveAttributeSearchElementsDesc=CSS selector of elements to include
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeRootDesc) A very short string to
+# describe the 'root' parameter to the 'pagemod remove attribute' command, which
+# is displayed in a dialog when the user is using this command.
+pagemodRemoveAttributeRootDesc=CSS selector of root of search
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeIgnoreCaseDesc) A very short string
+# to describe the 'ignoreCase' parameter to the 'pagemod remove attribute'
+# command, which is displayed in a dialog when the user is using this command.
+pagemodRemoveAttributeIgnoreCaseDesc=Perform case-insensitive search
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeResult) A string displayed as the
+# result of the 'pagemod remove attribute' command.
+pagemodRemoveAttributeResult=Elements matched by selector: %1$S. Attributes removed: %2$S.
+
+# LOCALIZATION NOTE (cookieDesc) A very short description of the 'cookie'
+# command. See cookieManual for a fuller description of what it does. This
+# string is designed to be shown in a menu alongside the command name, which
+# is why it should be as short as possible.
+cookieDesc=Display and alter cookies
+
+# LOCALIZATION NOTE (cookieManual) A fuller description of the 'cookie'
+# command, displayed when the user asks for help on what it does.
+cookieManual=Commands to list, create, delete and alter cookies for the current domain.
+
+# LOCALIZATION NOTE (cookieListDesc) A very short description of the
+# 'cookie list' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+cookieListDesc=Display cookies
+
+# LOCALIZATION NOTE (cookieListManual) A fuller description of the 'cookie list'
+# command, displayed when the user asks for help on what it does.
+cookieListManual=Display a list of the cookies relevant to the current page.
+
+# LOCALIZATION NOTE (cookieListOutKey) A heading used in the output from the
+# 'cookie list' command above a list of cookie keys
+cookieListOutKey=Key
+
+# LOCALIZATION NOTE (cookieListOutValue) A heading used in the output from the
+# 'cookie list' command above a list of cookie values
+cookieListOutValue=Value
+
+# LOCALIZATION NOTE (cookieListOutActions) A heading used in the output from the
+# 'cookie list' command above a list of actions to take on cookies
+cookieListOutActions=Actions
+
+# LOCALIZATION NOTE (cookieListOutEdit) A title used in the output from the
+# 'cookie list' command on a button which can be used to edit cookie values
+cookieListOutEdit=Edit
+
+# LOCALIZATION NOTE (cookieListOutRemove) A title used in the output from the
+# 'cookie list' command on a button which can be used to remove cookies
+cookieListOutRemove=Remove
+
+# LOCALIZATION NOTE (cookieRemoveDesc) A very short description of the
+# 'cookie remove' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+cookieRemoveDesc=Remove a cookie
+
+# LOCALIZATION NOTE (cookieRemoveManual) A fuller description of the 'cookie remove'
+# command, displayed when the user asks for help on what it does.
+cookieRemoveManual=Remove a cookie, given its key
+
+# LOCALIZATION NOTE (cookieRemoveKeyDesc) A very short string to describe the
+# 'key' parameter to the 'cookie remove' command, which is displayed in a dialog
+# when the user is using this command.
+cookieRemoveKeyDesc=The key of the cookie to remove
+
+# LOCALIZATION NOTE (cookieSetDesc) A very short description of the
+# 'cookie set' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+cookieSetDesc=Set a cookie
+
+# LOCALIZATION NOTE (cookieSetManual) A fuller description of the 'cookie set'
+# command, displayed when the user asks for help on what it does.
+cookieSetManual=Set a cookie by specifying a key name, it's value and optionally one or more of the following attributes: expires (max-age in seconds or the expires date in GMTString format), path, domain, secure
+
+# LOCALIZATION NOTE (cookieSetKeyDesc) A very short string to describe the
+# 'key' parameter to the 'cookie set' command, which is displayed in a dialog
+# when the user is using this command.
+cookieSetKeyDesc=The key of the cookie to set
+
+# LOCALIZATION NOTE (cookieSetValueDesc) A very short string to describe the
+# 'value' parameter to the 'cookie set' command, which is displayed in a dialog
+# when the user is using this command.
+cookieSetValueDesc=The value of the cookie to set
+
+# LOCALIZATION NOTE (cookieSetOptionsDesc) The title of a set of options to
+# the 'cookie set' command, displayed as a heading to the list of option.
+cookieSetOptionsDesc=Options
+
+# LOCALIZATION NOTE (cookieSetPathDesc) A very short string to describe the
+# 'path' parameter to the 'cookie set' command, which is displayed in a dialog
+# when the user is using this command.
+cookieSetPathDesc=The path of the cookie to set
+
+# LOCALIZATION NOTE (cookieSetDomainDesc) A very short string to describe the
+# 'domain' parameter to the 'cookie set' command, which is displayed in a dialog
+# when the user is using this command.
+cookieSetDomainDesc=The domain of the cookie to set
+
+# LOCALIZATION NOTE (cookieSetSecureDesc) A very short string to describe the
+# 'secure' parameter to the 'cookie set' command, which is displayed in a dialog
+# when the user is using this command.
+cookieSetSecureDesc=Only transmitted over https
--- a/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
@@ -145,16 +145,21 @@ webConsolePositionBelow=Below
webConsolePositionWindow=Window
# LOCALIZATION NOTE (webConsoleWindowTitleAndURL): The Web Console floating
# panel title, followed by the web page URL.
# For RTL languages you need to set the LRM in the string to give the URL
# the correct direction.
webConsoleWindowTitleAndURL=Web Console - %S
+# LOCALIZATION NOTE (webConsoleMixedContentWarning): Message displayed after a
+# URL in the Web Console that has been flagged for Mixed Content (i.e. http
+# content in an https page)
+webConsoleMixedContentWarning=Mixed Content
+
# LOCALIZATION NOTE (scratchpad.linkText):
# The text used in the right hand side of the web console command line when
# Javascript is being entered, to indicate how to jump into scratchpad mode
scratchpad.linkText=Shift+RETURN - Open in Scratchpad
# LOCALIZATION NOTE (gcliterm.instanceLabel): The console displays
# objects using their type (from the constructor function) in this descriptive
# string
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -115,12 +115,13 @@
% override chrome://mozapps/locale/downloads/settingsChange.dtd chrome://browser/locale/downloads/settingsChange.dtd
% locale testpilot @AB_CD@ %locale/feedback/
locale/feedback/main.dtd (%feedback/main.dtd)
locale/feedback/main.properties (%feedback/main.properties)
% locale pdf.js @AB_CD@ %locale/pdfviewer/
locale/pdfviewer/viewer.properties (%pdfviewer/viewer.properties)
locale/pdfviewer/chrome.properties (%pdfviewer/chrome.properties)
#ifdef MOZ_WEBAPP_RUNTIME
+../webapprt/chrome/@AB_CD@.jar:
% locale webapprt @AB_CD@ %locale/webapprt/
locale/webapprt/webapp.dtd (%webapprt/webapp.dtd)
locale/webapprt/webapp.properties (%webapprt/webapp.properties)
#endif
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -581,17 +581,17 @@ toolbar[mode="full"] .toolbarbutton-1 >
#forward-button[disabled] {
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar&state=disabled");
}
#forward-button[disabled]:-moz-locale-dir(rtl) {
list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar&state=disabled");
}
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
- -moz-transition: @forwardTransitionLength@ ease-out;
+ transition: @forwardTransitionLength@ ease-out;
}
@conditionalForwardWithUrlbar@ > #forward-button[disabled] {
-moz-transform: scale(0);
opacity: 0;
pointer-events: none;
}
@@ -933,18 +933,18 @@ toolbar[iconsize="small"] #feed-button {
-moz-margin-start: -@conditionalForwardWithUrlbarWidth_small@px;
}
@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar {
pointer-events: all;
}
@conditionalForwardWithUrlbar@:not([switchingtabs]) + #urlbar-container > #urlbar {
- -moz-transition: margin-left @forwardTransitionLength@ ease-out,
- margin-right @forwardTransitionLength@ ease-out;
+ transition: margin-left @forwardTransitionLength@ ease-out,
+ margin-right @forwardTransitionLength@ ease-out;
}
@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar:-moz-locale-dir(ltr) {
margin-left: -@conditionalForwardWithUrlbarWidth@px;
}
@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
margin-right: -@conditionalForwardWithUrlbarWidth@px;
}
@@ -1637,23 +1637,23 @@ richlistitem[type~="action"][actiontype=
.tabbrowser-arrowscrollbox > .scrollbutton-up {
-moz-border-start: 0;
-moz-border-end: 2px solid transparent;
}
.tabbrowser-arrowscrollbox > .scrollbutton-down {
-moz-border-start: 2px solid transparent;
-moz-border-end: 0;
- -moz-transition: 1s box-shadow ease-out;
+ transition: 1s box-shadow ease-out;
border-radius: 4px;
}
.tabbrowser-arrowscrollbox > .scrollbutton-down[notifybgtab] {
box-shadow: 0 0 5px 5px Highlight inset;
- -moz-transition: none;
+ transition: none;
}
.tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]):-moz-locale-dir(ltr),
.tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled]):-moz-locale-dir(rtl) {
border-width: 0 2px 0 0;
border-style: solid;
-moz-border-image: url("chrome://browser/skin/tabbrowser/tab-overflow-border.png") 0 2 0 2 fill;
}
--- a/browser/themes/gnomestripe/devtools/debugger.css
+++ b/browser/themes/gnomestripe/devtools/debugger.css
@@ -98,27 +98,27 @@
*/
.variable {
-moz-margin-start: 1px;
-moz-margin-end: 1px;
margin-top: 2px;
border-bottom: 1px dotted #ddd;
border-radius: 8px;
- -moz-transition: background 1s ease-in-out;
+ transition: background 1s ease-in-out;
background: #fff;
}
.variable[changed] {
- -moz-transition-duration: 0.4s;
+ transition-duration: 0.4s;
background: rgba(255, 255, 0, 0.65);
}
.variable[added] {
- -moz-transition-duration: 0.4s;
+ transition-duration: 0.4s;
background: rgba(0, 255, 0, 0.15);
}
.variable > .title > .arrow {
margin-top: -2px;
}
.variable > .title > .name {
--- a/browser/themes/gnomestripe/devtools/gcli.css
+++ b/browser/themes/gnomestripe/devtools/gcli.css
@@ -124,8 +124,13 @@
color: hsl(25,78%,50%);
}
.gcli-menu-more {
font-size: 80%;
text-align: right;
-moz-padding-end: 8px;
}
+
+.gcli-addon-disabled {
+ opacity: 0.6;
+ text-decoration: line-through;
+}
--- a/browser/themes/gnomestripe/devtools/webconsole.css
+++ b/browser/themes/gnomestripe/devtools/webconsole.css
@@ -3,17 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.hud-box {
border-bottom: 1px solid #aaa;
text-shadow: none;
}
.hud-box.animated {
- -moz-transition: height 100ms;
+ transition: height 100ms;
}
.hud-splitter {
box-shadow: 0 -1px 0 0 ThreeDShadow inset, 0 0 0 10px -moz-Dialog inset;
}
.hud-outer-wrapper {
width: 100%;
@@ -89,16 +89,25 @@
margin-top: 0;
margin-bottom: 0;
-moz-margin-start: 0;
-moz-margin-end: 6px;
width: 10em;
text-align: end;
}
+.webconsole-mixed-content {
+ color: #FF0000;
+}
+
+.webconsole-mixed-content-link {
+ color: #0000EE;
+ margin: 0;
+}
+
.hud-msg-node[selected="true"] > .webconsole-timestamp,
.hud-msg-node[selected="true"] > .webconsole-location {
color: inherit;
}
.jsterm-input-node,
.jsterm-complete-node {
font: 12px "DejaVu Sans Mono", monospace;
--- a/browser/themes/gnomestripe/downloads/downloads.css
+++ b/browser/themes/gnomestripe/downloads/downloads.css
@@ -15,17 +15,17 @@
color: inherit;
}
#downloadsPanel:not([hasdownloads]) > #downloadsListBox {
display: none;
}
#downloadsHistory {
- background: inherit;
+ background: transparent;
color: -moz-nativehyperlinktext;
cursor: pointer;
}
#downloadsPanel[hasdownloads] > #downloadsHistory {
border-top: 1px solid ThreeDShadow;
background-image: -moz-linear-gradient(hsla(0,0%,0%,.15), hsla(0,0%,0%,.08) 6px);
}
--- a/browser/themes/gnomestripe/newtab/newTab.css
+++ b/browser/themes/gnomestripe/newtab/newTab.css
@@ -39,17 +39,17 @@
/* CELLS */
.newtab-cell {
-moz-margin-end: 20px;
background-color: rgba(255,255,255,.2);
border: 1px solid;
border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
border-radius: 1px;
- -moz-transition: border-color 100ms ease-out;
+ transition: border-color 100ms ease-out;
}
.newtab-cell:empty {
border: 1px dashed;
border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
}
.newtab-cell:last-child {
@@ -58,26 +58,26 @@
.newtab-cell:hover:not(:empty):not([dragged]) {
border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
}
/* SITES */
.newtab-site {
text-decoration: none;
- -moz-transition-property: top, left, opacity, box-shadow, background-color;
+ transition-property: top, left, opacity, box-shadow, background-color;
}
.newtab-site:hover,
.newtab-site[dragged] {
box-shadow: 0 0 10px rgba(8,22,37,.3);
}
.newtab-site[dragged] {
- -moz-transition-property: box-shadow, background-color;
+ transition-property: box-shadow, background-color;
background-color: rgb(242,242,242);
}
/* THUMBNAILS */
.newtab-thumbnail {
background-origin: padding-box;
background-clip: padding-box;
background-repeat: no-repeat;
--- a/browser/themes/gnomestripe/tabview/tabview.css
+++ b/browser/themes/gnomestripe/tabview/tabview.css
@@ -121,19 +121,19 @@ html[dir=rtl] .expander {
.expander:hover {
opacity: 1.0;
}
.close:hover,
.expander:hover,
.appTabIcon:hover {
- -moz-transition-property: opacity;
- -moz-transition-duration: 0.5s;
- -moz-transition-timing-function: ease-out;
+ transition-property: opacity;
+ transition-duration: 0.5s;
+ transition-timing-function: ease-out;
}
.favicon img:hover,
.close img:hover,
.expander img:hover {
opacity: 1;
border: none;
}
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -521,17 +521,17 @@ toolbar[mode="icons"] #forward-button {
}
@conditionalForwardWithUrlbar@ > #forward-button:-moz-lwtheme {
-moz-padding-start: 2px;
-moz-padding-end: 0;
}
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
- -moz-transition: opacity @forwardTransitionLength@ ease-out;
+ transition: opacity @forwardTransitionLength@ ease-out;
}
@conditionalForwardWithUrlbar@ > #forward-button:hover:active:not(:-moz-lwtheme) {
background-image: -moz-linear-gradient(hsl(0,0%,74%), hsl(0,0%,61%));
box-shadow: inset rgba(0,0,0,.3) 0 -6px 10px,
inset #000 0 1px 3px,
inset rgba(0,0,0,.2) 0 1px 3px,
0 1px 0 hsla(0,0%,100%,.2);
@@ -890,17 +890,17 @@ toolbar[mode="icons"] #zoom-in-button {
@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar {
-moz-border-start: none;
margin-left: 0;
pointer-events: all;
}
@conditionalForwardWithUrlbar@:not([switchingtabs]) + #urlbar-container > #urlbar {
- -moz-transition: margin-left @forwardTransitionLength@ ease-out;
+ transition: margin-left @forwardTransitionLength@ ease-out;
}
@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(ltr) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
@@ -913,17 +913,17 @@ toolbar[mode="icons"] #zoom-in-button {
}
@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar {
margin-left: -@conditionalForwardWithUrlbarWidth@px;
}
@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar {
/* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
- -moz-transition-delay: 100s;
+ transition-delay: 100s;
}
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar {
/* when not hovered anymore, trigger a new transition to hide the forward button immediately */
margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
}
@conditionalForwardWithUrlbar@ + #urlbar-container:-moz-locale-dir(rtl),
@@ -956,28 +956,28 @@ toolbar[mode="icons"] #zoom-in-button {
border-radius: 0;
}
@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar > #identity-box {
border-radius: 0;
}
@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
- -moz-transition: 0s padding-left;
+ transition: 0s padding-left;
padding-left: 10px;
}
@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
- -moz-transition: 0s padding-right;
+ transition: 0s padding-right;
padding-right: 10px;
}
@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box {
/* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
- -moz-transition-delay: 100s;
+ transition-delay: 100s;
}
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
padding-left: 10.01px;
}
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
padding-right: 10.01px;
@@ -1668,19 +1668,19 @@ toolbarbutton.chevron > .toolbarbutton-m
list-style-image: url("chrome://browser/skin/tabbrowser/loading.png");
}
.tabbrowser-tab:not(:hover) > .tab-stack > .tab-content > .tab-icon-image:not([selected="true"]) {
opacity: .8;
}
.tabbrowser-tab:not([pinned]):not([fadein]) {
- -moz-transition: min-width 200ms ease-out /* copied from browser/base/content/browser.css */,
- max-width 250ms ease-out /* copied from browser/base/content/browser.css */,
- opacity 50ms ease-out 100ms /* hide the tab for the last 100ms of the max-width transition */;
+ transition: min-width 200ms ease-out /* copied from browser/base/content/browser.css */,
+ max-width 250ms ease-out /* copied from browser/base/content/browser.css */,
+ opacity 50ms ease-out 100ms /* hide the tab for the last 100ms of the max-width transition */;
}
.tab-stack {
/* ensure stable tab height with and without toolbarbuttons on the tab bar */
height: 26px;
}
.tabbrowser-tab,
@@ -2010,22 +2010,22 @@ toolbarbutton.chevron > .toolbarbutton-m
}
.tabbrowser-arrowscrollbox > .scrollbutton-up {
-moz-border-end: 2px solid transparent;
}
.tabbrowser-arrowscrollbox > .scrollbutton-down {
-moz-border-start: 2px solid transparent;
- -moz-transition: 1s background-color ease-out;
+ transition: 1s background-color ease-out;
}
.tabbrowser-arrowscrollbox > .scrollbutton-down[notifybgtab] {
background-color: Highlight;
- -moz-transition: none;
+ transition: none;
}
.tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-locale-dir(ltr),
.tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-locale-dir(rtl) {
list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-left.png");
}
.tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-locale-dir(ltr),
@@ -2732,16 +2732,30 @@ panel[dimmed="true"] {
-moz-border-start: 1px solid #242b33;
min-width: 0;
width: 3px;
background-color: transparent;
-moz-margin-end: -3px;
position: relative;
}
+/* Lion Fullscreen window styling */
+@media (-moz-mac-lion-theme) {
+ #navigator-toolbox[inFullscreen][tabsontop="true"]:not(:-moz-lwtheme)::before {
+ height: 36px;
+ }
+ #main-window[inFullscreen]:-moz-lwtheme {
+ /* This additional padding matches the change in height in the pseudo-element
+ * above. The rules combined force the top 22px of the background image to
+ * be hidden, so there image doesn't jump around with the loss of the titlebar */
+ padding-top: 11px;
+ background-position: right -11px;
+ }
+}
+
#devtools-sidebar-box {
background-color: -moz-Field;
}
/* Highlighter - Node Infobar */
#highlighter-nodeinfobar {
color: hsl(200, 100%, 65%);
--- a/browser/themes/pinstripe/devtools/debugger.css
+++ b/browser/themes/pinstripe/devtools/debugger.css
@@ -100,27 +100,27 @@
*/
.variable {
-moz-margin-start: 1px;
-moz-margin-end: 1px;
margin-top: 2px;
border-bottom: 1px dotted #ddd;
border-radius: 8px;
- -moz-transition: background 1s ease-in-out;
+ transition: background 1s ease-in-out;
background: #fff;
}
.variable[changed] {
- -moz-transition-duration: 0.4s;
+ transition-duration: 0.4s;
background: rgba(255, 255, 0, 0.65);
}
.variable[added] {
- -moz-transition-duration: 0.4s;
+ transition-duration: 0.4s;
background: rgba(0, 255, 0, 0.15);
}
.variable > .title > .arrow {
margin-top: -2px;
}
.variable > .title > .name {
--- a/browser/themes/pinstripe/devtools/gcli.css
+++ b/browser/themes/pinstripe/devtools/gcli.css
@@ -126,8 +126,13 @@
color: hsl(25,78%,50%);
}
.gcli-menu-more {
font-size: 80%;
text-align: right;
-moz-padding-end: 8px;
}
+
+.gcli-addon-disabled {
+ opacity: 0.6;
+ text-decoration: line-through;
+}
--- a/browser/themes/pinstripe/devtools/webconsole.css
+++ b/browser/themes/pinstripe/devtools/webconsole.css
@@ -5,17 +5,17 @@
%include ../shared.inc
.hud-box {
border-bottom: 1px solid #aaa;
text-shadow: none;
}
.hud-box.animated {
- -moz-transition: height 100ms;
+ transition: height 100ms;
}
.hud-splitter {
border-bottom: solid #a5a5a5 1px;
background: url("chrome://global/skin/splitter/dimple.png") no-repeat center,
-moz-linear-gradient(top, #fcfcfc, #dfdfdf);
}
@@ -249,16 +249,25 @@
.webconsole-msg-console.webconsole-msg-warn {
-moz-image-region: rect(24px, 24px, 32px, 16px);
}
.webconsole-msg-console.webconsole-msg-info {
-moz-image-region: rect(24px, 32px, 32px, 24px);
}
+.webconsole-mixed-content {
+ color: #FF0000;
+}
+
+.webconsole-mixed-content-link {
+ color: #0000EE;
+ margin: 0;
+}
+
/* Input and output styles */
.webconsole-msg-input > .webconsole-msg-icon-container,
.webconsole-msg-output > .webconsole-msg-icon-container {
border-left: solid #808080 6px;
}
.webconsole-msg-input {
-moz-image-region: rect(24px, 40px, 32px, 32px);
--- a/browser/themes/pinstripe/downloads/downloads.css
+++ b/browser/themes/pinstripe/downloads/downloads.css
@@ -15,17 +15,17 @@
color: inherit;
}
#downloadsPanel:not([hasdownloads]) > #downloadsListBox {
display: none;
}
#downloadsHistory {
- background: inherit;
+ background: transparent;
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
color: hsl(210,100%,75%);
cursor: pointer;
}
#downloadsPanel:not([hasdownloads]) > #downloadsHistory {
border-top-left-radius: 6px;
--- a/browser/themes/pinstripe/newtab/newTab.css
+++ b/browser/themes/pinstripe/newtab/newTab.css
@@ -39,17 +39,17 @@
/* CELLS */
.newtab-cell {
-moz-margin-end: 20px;
background-color: rgba(255,255,255,.2);
border: 1px solid;
border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
border-radius: 1px;
- -moz-transition: border-color 100ms ease-out;
+ transition: border-color 100ms ease-out;
}
.newtab-cell:empty {
border: 1px dashed;
border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
}
.newtab-cell:last-child {
@@ -58,26 +58,26 @@
.newtab-cell:hover:not(:empty):not([dragged]) {
border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
}
/* SITES */
.newtab-site {
text-decoration: none;
- -moz-transition-property: top, left, opacity, box-shadow, background-color;
+ transition-property: top, left, opacity, box-shadow, background-color;
}
.newtab-site:hover,
.newtab-site[dragged] {
box-shadow: 0 0 10px rgba(8,22,37,.3);
}
.newtab-site[dragged] {
- -moz-transition-property: box-shadow, background-color;
+ transition-property: box-shadow, background-color;
background-color: rgb(242,242,242);
}
/* THUMBNAILS */
.newtab-thumbnail {
background-origin: padding-box;
background-clip: padding-box;
background-repeat: no-repeat;
--- a/browser/themes/pinstripe/tabview/tabview.css
+++ b/browser/themes/pinstripe/tabview/tabview.css
@@ -102,33 +102,33 @@ html[dir=rtl] .close {
}
.expander {
bottom: 8px;
right: 6px;
width: 16px;
height: 16px;
background: url(chrome://global/skin/icons/resizer.png) no-repeat;
- -moz-transition-property: opacity;
- -moz-transition-duration: 0.5s;
- -moz-transition-timing-function: ease-out;
+ transition-property: opacity;
+ transition-duration: 0.5s;
+ transition-timing-function: ease-out;
opacity: 0.2;
}
html[dir=rtl] .expander {
right: auto;
left: 6px;
-moz-transform: scaleX(-1);
}
.expander:hover,
.appTabIcon:hover {
- -moz-transition-property: opacity;
- -moz-transition-duration: 0.5s;
- -moz-transition-timing-function: ease-out;
+ transition-property: opacity;
+ transition-duration: 0.5s;
+ transition-timing-function: ease-out;
opacity: 1.0;
}
.favicon img:hover,
.expander img:hover {
opacity: 1;
border: none;
}
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -354,17 +354,17 @@
border-top: 1px solid #d6e5f5;
border-bottom: none;
}
.appmenu-edit-button:not([disabled]):hover {
border: 1px solid #b8d6fb;
box-shadow: inset 0 0 1px white;
background: -moz-linear-gradient(#fafbfd, #ebf3fd);
- -moz-transition: .2s ease-in;
+ transition: .2s ease-in;
}
}
#appmenuSecondaryPane-spacer {
min-height: 1em;
}
#appmenu-editmenu {
@@ -694,18 +694,18 @@ toolbar[mode=full] .toolbarbutton-1 > .t
padding: 2px 6px;
background: hsla(210,32%,93%,0) padding-box;
border-radius: 2px;
border: 1px solid;
border-color: hsla(210,54%,20%,0) hsla(210,54%,20%,0) hsla(210,54%,20%,0);
box-shadow: 0 1px hsla(0,0%,100%,0) inset,
0 1px hsla(210,54%,20%,0),
0 0 2px hsla(210,54%,20%,0);
- -moz-transition-property: background-color, border-color, box-shadow;
- -moz-transition-duration: 150ms;
+ transition-property: background-color, border-color, box-shadow;
+ transition-duration: 150ms;
}
@navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
@navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
padding: 3px 7px;
}
@navbarLargeIcons@ .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button) > .toolbarbutton-icon,
@@ -774,26 +774,26 @@ toolbar[mode=full] .toolbarbutton-1 > .t
background-color: hsla(210,54%,20%,.15);
border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
0 0 1px hsla(210,54%,20%,.2) inset,
/* allows winstripe-keyhole-forward-clip-path to be used for non-hover as well as hover: */
0 1px 0 hsla(210,54%,20%,0),
0 0 2px hsla(210,54%,20%,0);
text-shadow: none;
- -moz-transition: none;
+ transition: none;
}
@navbarLargeIcons@ .toolbarbutton-1:-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon {
-moz-border-start-color: hsla(210,54%,20%,.35);
}
@navbarLargeIcons@ .toolbarbutton-1[checked]:not(:active):hover > .toolbarbutton-icon {
background-color: rgba(90%,90%,90%,.4);
- -moz-transition: background-color .4s;
+ transition: background-color .4s;
}
:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1,
:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button,
.tabbrowser-arrowscrollbox > .scrollbutton-up,
.tabbrowser-arrowscrollbox > .scrollbutton-down {
-moz-appearance: none;
border-style: none;
@@ -858,17 +858,17 @@ toolbar[mode=full] .toolbarbutton-1 > .t
-moz-margin-start: -6px !important;
border-left-style: none;
border-radius: 0;
padding-left: 7px;
padding-right: 3px;
}
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
- -moz-transition: opacity @forwardTransitionLength@ ease-out;
+ transition: opacity @forwardTransitionLength@ ease-out;
}
@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] {
opacity: 0;
}
@conditionalForwardWithUrlbar@ > #back-button {
-moz-image-region: rect(18px, 20px, 38px, 0);
@@ -893,18 +893,18 @@ toolbar[mode=full] .toolbarbutton-1 > .t
border-radius: 10000px;
padding: 5px;
border: none;
background-image: -moz-linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
0 0 0 1px hsla(0,0%,100%,.3) inset,
0 0 0 1px hsla(210,54%,20%,.25),
0 1px 0 hsla(210,54%,20%,.35);
- -moz-transition-property: background-color, box-shadow;
- -moz-transition-duration: 250ms;
+ transition-property: background-color, box-shadow;
+ transition-duration: 250ms;
}
@conditionalForwardWithUrlbar@ > #back-button:not([disabled="true"]):not([open="true"]):not(:active):hover > .toolbarbutton-icon {
background-color: hsla(210,48%,96%,.75);
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
0 0 0 1px hsla(0,0%,100%,.3) inset,
0 0 0 1px hsla(210,54%,20%,.3),
0 1px 0 hsla(210,54%,20%,.4),
@@ -913,23 +913,23 @@ toolbar[mode=full] .toolbarbutton-1 > .t
@conditionalForwardWithUrlbar@ > #back-button:not([disabled="true"]):hover:active > .toolbarbutton-icon,
@conditionalForwardWithUrlbar@ > #back-button[open="true"] > .toolbarbutton-icon {
background-color: hsla(210,54%,20%,.15);
box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
0 0 1px hsla(210,54%,20%,.2) inset,
0 0 0 1px hsla(210,54%,20%,.4),
0 1px 0 hsla(210,54%,20%,.2);
- -moz-transition: none;
+ transition: none;
}
@conditionalForwardWithUrlbar@ > #back-button[disabled] > .toolbarbutton-icon {
box-shadow: 0 0 0 1px hsla(210,54%,20%,.55),
0 1px 0 hsla(210,54%,20%,.65);
- -moz-transition: none;
+ transition: none;
}
.unified-nav-back[_moz-menuactive]:-moz-locale-dir(ltr),
.unified-nav-forward[_moz-menuactive]:-moz-locale-dir(rtl) {
list-style-image: url("chrome://browser/skin/menu-back.png") !important;
}
.unified-nav-forward[_moz-menuactive]:-moz-locale-dir(ltr),
@@ -1197,17 +1197,17 @@ toolbar[mode=full] .toolbarbutton-1 > .t
@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar {
-moz-border-start: none;
margin-left: 0;
pointer-events: all;
}
@conditionalForwardWithUrlbar@:not([switchingtabs]) + #urlbar-container > #urlbar {
- -moz-transition: margin-left @forwardTransitionLength@ ease-out;
+ transition: margin-left @forwardTransitionLength@ ease-out;
}
@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(ltr) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
@@ -1220,17 +1220,17 @@ toolbar[mode=full] .toolbarbutton-1 > .t
}
@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar {
margin-left: -@conditionalForwardWithUrlbarWidth@px;
}
@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar {
/* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
- -moz-transition-delay: 100s;
+ transition-delay: 100s;
}
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar {
/* when not hovered anymore, trigger a new transition to hide the forward button immediately */
margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
}
@conditionalForwardWithUrlbar@ + #urlbar-container:-moz-locale-dir(rtl),
@@ -1336,27 +1336,27 @@ html|*.urlbar-input:-moz-lwtheme:-moz-pl
}
@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar > #identity-box {
border-radius: 0;
}
@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
padding-left: 5px;
- -moz-transition: padding-left;
+ transition: padding-left;
}
@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
padding-right: 5px;
- -moz-transition: padding-right;
+ transition: padding-right;
}
@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box {
/* forward button hiding is delayed when hovered */
- -moz-transition-delay: 100s;
+ transition-delay: 100s;
}
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
/* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
padding-left: 5.01px;
}
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
@@ -1960,22 +1960,22 @@ richlistitem[type~="action"][actiontype=
}
.tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-locale-dir(rtl),
.tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-locale-dir(ltr) {
-moz-transform: scaleX(-1);
}
.tabbrowser-arrowscrollbox > .scrollbutton-down {
- -moz-transition: 1s background-color ease-out;
+ transition: 1s background-color ease-out;
}
.tabbrowser-arrowscrollbox > .scrollbutton-down[notifybgtab] {
background-color: Highlight;
- -moz-transition: none;
+ transition: none;
}
.tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]),
.tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled]) {
border-width: 0 2px 0 0;
border-style: solid;
-moz-border-image: url("chrome://browser/skin/tabbrowser/tab-overflow-border.png") 0 2 0 2 fill;
}
--- a/browser/themes/winstripe/devtools/common.css
+++ b/browser/themes/winstripe/devtools/common.css
@@ -87,19 +87,19 @@
background-color: transparent;
background-image: url(magnifying-glass.png), -moz-linear-gradient(hsla(210,16%,76%,.15), hsla(210,16%,76%,.35));
background-repeat: no-repeat;
background-position: 4px center, top left, top left;
padding-top: 0;
padding-bottom: 0;
-moz-padding-start: 18px;
-moz-padding-end: 12px;
- -moz-transition-property: background-color, border-color, box-shadow;
- -moz-transition-duration: 150ms;
- -moz-transition-timing-function: ease;
+ transition-property: background-color, border-color, box-shadow;
+ transition-duration: 150ms;
+ transition-timing-function: ease;
color: inherit;
}
.devtools-searchinput[focused] {
border-color: hsl(200,70%,40%) hsl(200,75%,37%) hsl(200,80%,35%);
background-origin: padding-box;
background-clip: padding-box;
box-shadow: inset 0 0 0 1px hsla(211,68%,6%,.1);
--- a/browser/themes/winstripe/devtools/debugger.css
+++ b/browser/themes/winstripe/devtools/debugger.css
@@ -98,27 +98,27 @@
*/
.variable {
-moz-margin-start: 1px;
-moz-margin-end: 1px;
margin-top: 2px;
border-bottom: 1px dotted #ddd;
border-radius: 8px;
- -moz-transition: background 1s ease-in-out;
+ transition: background 1s ease-in-out;
background: #fff;
}
.variable[changed] {
- -moz-transition-duration: 0.4s;
+ transition-duration: 0.4s;
background: rgba(255, 255, 0, 0.65);
}
.variable[added] {
- -moz-transition-duration: 0.4s;
+ transition-duration: 0.4s;
background: rgba(0, 255, 0, 0.15);
}
.variable > .title > .arrow {
margin-top: -2px;
}
.variable > .title > .name {
--- a/browser/themes/winstripe/devtools/gcli.css
+++ b/browser/themes/winstripe/devtools/gcli.css
@@ -124,8 +124,13 @@
color: hsl(25,78%,50%);
}
.gcli-menu-more {
font-size: 80%;
text-align: right;
-moz-padding-end: 8px;
}
+
+.gcli-addon-disabled {
+ opacity: 0.6;
+ text-decoration: line-through;
+}
--- a/browser/themes/winstripe/devtools/webconsole.css
+++ b/browser/themes/winstripe/devtools/webconsole.css
@@ -3,17 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.hud-box {
border-bottom: 1px solid #aaa;
text-shadow: none;
}
.hud-box.animated {
- -moz-transition: height 100ms;
+ transition: height 100ms;
}
.hud-splitter {
border-top: none;
}
.hud-outer-wrapper {
width: 100%;
@@ -200,16 +200,25 @@
.webconsole-msg-console.webconsole-msg-warn {
-moz-image-region: rect(24px, 24px, 32px, 16px);
}
.webconsole-msg-console.webconsole-msg-info {
-moz-image-region: rect(24px, 32px, 32px, 24px);
}
+.webconsole-mixed-content {
+ color: #FF0000;
+}
+
+.webconsole-mixed-content-link {
+ color: #0000EE;
+ margin: 0;
+}
+
/* Input and output styles */
.webconsole-msg-input > .webconsole-msg-icon-container,
.webconsole-msg-output > .webconsole-msg-icon-container {
border-left: solid #808080 6px;
}
.webconsole-msg-input {
-moz-image-region: rect(24px, 40px, 32px, 32px);
--- a/browser/themes/winstripe/downloads/downloads.css
+++ b/browser/themes/winstripe/downloads/downloads.css
@@ -25,17 +25,17 @@
#downloadsListBox {
width: 60ch;
background-color: transparent;
padding: 4px;
color: inherit;
}
#downloadsHistory {
- background: inherit;
+ background: transparent;
color: -moz-nativehyperlinktext;
cursor: pointer;
}
#downloadsHistory > .button-box {
margin: 1em;
}
--- a/browser/themes/winstripe/newtab/newTab.css
+++ b/browser/themes/winstripe/newtab/newTab.css
@@ -39,17 +39,17 @@
/* CELLS */
.newtab-cell {
-moz-margin-end: 20px;
background-color: rgba(255,255,255,.2);
border: 1px solid;
border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
border-radius: 1px;
- -moz-transition: border-color 100ms ease-out;
+ transition: border-color 100ms ease-out;
}
.newtab-cell:empty {
border: 1px dashed;
border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
}
.newtab-cell:last-child {
@@ -58,26 +58,26 @@
.newtab-cell:hover:not(:empty):not([dragged]) {
border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
}
/* SITES */
.newtab-site {
text-decoration: none;
- -moz-transition-property: top, left, opacity, box-shadow, background-color;
+ transition-property: top, left, opacity, box-shadow, background-color;
}
.newtab-site:hover,
.newtab-site[dragged] {
box-shadow: 0 0 10px rgba(8,22,37,.3);
}
.newtab-site[dragged] {
- -moz-transition-property: box-shadow, background-color;
+ transition-property: box-shadow, background-color;
background-color: rgb(242,242,242);
}
/* THUMBNAILS */
.newtab-thumbnail {
background-origin: padding-box;
background-clip: padding-box;
background-repeat: no-repeat;
--- a/browser/themes/winstripe/tabview/tabview.css
+++ b/browser/themes/winstripe/tabview/tabview.css
@@ -103,33 +103,33 @@ html[dir=rtl] .close {
}
.expander {
bottom: 6px;
right: 6px;
width: 16px;
height: 16px;
background: url(chrome://global/skin/icons/resizer.png) no-repeat;
- -moz-transition-property: opacity;
- -moz-transition-duration: 0.5s;
- -moz-transition-timing-function: ease-out;
+ transition-property: opacity;
+ transition-duration: 0.5s;
+ transition-timing-function: ease-out;
opacity: 0.2;
}
html[dir=rtl] .expander {
right: auto;
left: 6px;
-moz-transform: scaleX(-1);
}
.expander:hover,
.appTabIcon:hover {
- -moz-transition-property: opacity;
- -moz-transition-duration: 0.5s;
- -moz-transition-timing-function: ease-out;
+ transition-property: opacity;
+ transition-duration: 0.5s;
+ transition-timing-function: ease-out;
opacity: 1.0;
}
.favicon img:hover,
.close img:hover,
.expander img:hover {
opacity: 1;
border: none;
new file mode 100644
--- /dev/null
+++ b/build/autoconf/zlib.m4
@@ -0,0 +1,54 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+dnl Usage: MOZ_ZLIB_CHECK([version])
+
+AC_DEFUN([MOZ_ZLIB_CHECK],
+[
+
+MOZZLIB=$1
+
+MOZ_ARG_WITH_STRING(system-zlib,
+[ --with-system-zlib[=PFX]
+ Use system libz [installed at prefix PFX]],
+ ZLIB_DIR=$withval)
+
+if test -z "$MOZ_ZLIB_LIBS$MOZ_ZLIB_CFLAGS$SKIP_LIBRARY_CHECKS"; then
+ _SAVE_CFLAGS=$CFLAGS
+ _SAVE_LDFLAGS=$LDFLAGS
+ _SAVE_LIBS=$LIBS
+
+ if test -n "${ZLIB_DIR}" -a "${ZLIB_DIR}" != "yes"; then
+ MOZ_ZLIB_CFLAGS="-I${ZLIB_DIR}/include"
+ MOZ_ZLIB_LIBS="-L${ZLIB_DIR}/lib"
+ CFLAGS="$MOZ_ZLIB_CFLAGS $CFLAGS"
+ LDFLAGS="$MOZ_ZLIB_LIBS $LDFLAGS"
+ fi
+ if test -z "$ZLIB_DIR" -o "$ZLIB_DIR" = no; then
+ MOZ_NATIVE_ZLIB=
+ else
+ AC_CHECK_LIB(z, gzread, [MOZ_NATIVE_ZLIB=1 MOZ_ZLIB_LIBS="$MOZ_ZLIB_LIBS -lz"],
+ [MOZ_NATIVE_ZLIB=])
+ if test "$MOZ_NATIVE_ZLIB" = 1; then
+ MOZZLIBNUM=`echo $MOZZLIB | awk -F. changequote(<<, >>)'{printf "0x%x\n", (((<<$>>1 * 16 + <<$>>2) * 16) + <<$>>3) * 16 + <<$>>4}'changequote([, ])`
+ AC_TRY_COMPILE([ #include <stdio.h>
+ #include <string.h>
+ #include <zlib.h> ],
+ [ #if ZLIB_VERNUM < $MOZZLIBNUM
+ #error "Insufficient zlib version ($MOZZLIBNUM required)."
+ #endif ],
+ MOZ_NATIVE_ZLIB=1,
+ AC_MSG_ERROR([Insufficient zlib version for --with-system-zlib ($MOZZLIB required)]))
+ fi
+ fi
+ CFLAGS=$_SAVE_CFLAGS
+ LDFLAGS=$_SAVE_LDFLAGS
+ LIBS=$_SAVE_LIBS
+fi
+
+AC_SUBST(MOZ_ZLIB_CFLAGS)
+AC_SUBST(MOZ_ZLIB_LIBS)
+AC_SUBST(MOZ_NATIVE_ZLIB)
+
+])
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -453,27 +453,25 @@ class ShutdownLeakLogger(object):
self.seenShutdown = True
def parse(self):
leakingTests = self._parseLeakingTests()
if leakingTests:
totalWindows = sum(len(test["leakedWindows"]) for test in leakingTests)
totalDocShells = sum(len(test["leakedDocShells"]) for test in leakingTests)
- msgType = "INFO" if totalWindows + totalDocShells <= self.MAX_LEAK_COUNT else "UNEXPECTED-FAIL"
- self.logger.info("TEST-%s | ShutdownLeaks | leaked %d DOMWindow(s) and %d DocShell(s) until shutdown", msgType, totalWindows, totalDocShells)
+ msgType = "TEST-INFO" if totalWindows + totalDocShells <= self.MAX_LEAK_COUNT else "TEST-UNEXPECTED-FAIL"
+ self.logger.info("%s | ShutdownLeaks | leaked %d DOMWindow(s) and %d DocShell(s) until shutdown", msgType, totalWindows, totalDocShells)
for test in leakingTests:
- self.logger.info("\n[%s]", test["fileName"])
-
for url, count in self._zipLeakedWindows(test["leakedWindows"]):
- self.logger.info(" %d window(s) [url = %s]", count, url)
+ self.logger.info("%s | %s | leaked %d window(s) until shutdown [url = %s]", msgType, test["fileName"], count, url)
if test["leakedDocShells"]:
- self.logger.info(" %d docShell(s)", len(test["leakedDocShells"]))
+ self.logger.info("%s | %s | leaked %d docShell(s) until shutdown", msgType, test["fileName"], len(test["leakedDocShells"]))
def _logWindow(self, line):
created = line[:2] == "++"
id = self._parseValue(line, "serial")
# log line has invalid format
if not id:
return
--- a/build/mobile/b2gautomation.py
+++ b/build/mobile/b2gautomation.py
@@ -82,16 +82,21 @@ class B2GRemoteAutomation(Automation):
dumpDir = tempfile.mkdtemp()
self._devicemanager.getDirectory(self._remoteProfile + '/minidumps/', dumpDir)
automationutils.checkForCrashes(dumpDir, symbolsPath, self.lastTestSeen)
try:
shutil.rmtree(dumpDir)
except:
print "WARNING: unable to remove directory: %s" % (dumpDir)
+ def initializeProfile(self, profileDir, extraPrefs = [], useServerLocations = False):
+ # add b2g specific prefs
+ extraPrefs.extend(["browser.manifestURL='dummy (bug 772307)'"])
+ return Automation.initializeProfile(self, profileDir, extraPrefs, useServerLocations)
+
def buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs):
# if remote profile is specified, use that instead
if (self._remoteProfile):
profileDir = self._remoteProfile
cmd, args = Automation.buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs)
return app, args
--- a/build/mobile/devicemanagerADB.py
+++ b/build/mobile/devicemanagerADB.py
@@ -7,29 +7,29 @@ from devicemanager import DeviceManager,
import re
import os
import sys
import tempfile
class DeviceManagerADB(DeviceManager):
def __init__(self, host=None, port=20701, retrylimit=5, packageName='fennec',
- adbPath='adb', deviceSerial=None):
+ adbPath='adb', deviceSerial=None, deviceRoot=None):
self.host = host
self.port = port
self.retrylimit = retrylimit
self.retries = 0
self._sock = None
self.useRunAs = False
self.haveRoot = False
self.useDDCopy = False
self.useZip = False
self.packageName = None
self.tempDir = None
- self.deviceRoot = None
+ self.deviceRoot = deviceRoot
# the path to adb, or 'adb' to assume that it's on the PATH
self.adbPath = adbPath
# The serial number of the device to use with adb, used in cases
# where multiple devices are being managed by the same adb instance.
self.deviceSerial = deviceSerial
@@ -532,16 +532,23 @@ class DeviceManagerADB(DeviceManager):
return data.split()[3]
def getLocalHash(self, filename):
data = p = subprocess.Popen(["ls", "-l", filename], stdout=subprocess.PIPE).stdout.read()
return data.split()[4]
# Internal method to setup the device root and cache its value
def setupDeviceRoot(self):
+ # if self.deviceRoot is already set, create it if necessary, and use it
+ if self.deviceRoot:
+ if not self.dirExists(self.deviceRoot):
+ if not self.mkDir(self.deviceRoot):
+ raise DMError("Unable to create device root %s" % self.deviceRoot)
+ return
+
# /mnt/sdcard/tests is preferred to /data/local/tests, but this can be
# over-ridden by creating /data/local/tests
testRoot = "/data/local/tests"
if (self.dirExists(testRoot)):
self.deviceRoot = testRoot
return
for (basePath, subPath) in [('/mnt/sdcard', 'tests'),
--- a/build/mobile/devicemanagerSUT.py
+++ b/build/mobile/devicemanagerSUT.py
@@ -30,45 +30,42 @@ class DeviceManagerSUT(DeviceManager):
port = 0
debug = 2
retries = 0
tempRoot = os.getcwd()
base_prompt = '$>'
base_prompt_re = '\$\>'
prompt_sep = '\x00'
prompt_regex = '.*(' + base_prompt_re + prompt_sep + ')'
- agentErrorRE = re.compile('^##AGENT-WARNING##.*')
+ agentErrorRE = re.compile('^##AGENT-WARNING##\ ?(.*)')
# TODO: member variable to indicate error conditions.
# This should be set to a standard error from the errno module.
# So, for example, when an error occurs because of a missing file/directory,
# before returning, the function would do something like 'self.error = errno.ENOENT'.
# The error would be set where appropriate--so sendCMD() could set socket errors,
# pushFile() and other file-related commands could set filesystem errors, etc.
- def __init__(self, host, port = 20701, retrylimit = 5):
+ def __init__(self, host, port = 20701, retrylimit = 5, deviceRoot = None):
self.host = host
self.port = port
self.retrylimit = retrylimit
self.retries = 0
self._sock = None
+ self.deviceRoot = deviceRoot
if self.getDeviceRoot() == None:
raise BaseException("Failed to connect to SUT Agent and retrieve the device root.")
def _cmdNeedsResponse(self, cmd):
""" Not all commands need a response from the agent:
- * if the cmd matches the pushRE then it is the first half of push
- and therefore we want to wait until the second half before looking
- for a response
* rebt obviously doesn't get a response
* uninstall performs a reboot to ensure starting in a clean state and
so also doesn't look for a response
"""
- noResponseCmds = [re.compile('^push .*$'),
- re.compile('^rebt'),
+ noResponseCmds = [re.compile('^rebt'),
re.compile('^uninst .*$'),
re.compile('^pull .*$')]
for c in noResponseCmds:
if (c.match(cmd)):
return False
# If the command is not in our list, then it gets a response
@@ -114,53 +111,53 @@ class DeviceManagerSUT(DeviceManager):
re.compile('^uninst .*$')]
for c in socketClosingCmds:
if (c.match(cmd)):
return True
return False
- def sendCmds(self, cmdlist, outputfile, timeout = None, newline = True):
+ def sendCmds(self, cmdlist, outputfile, timeout = None):
'''
a wrapper for _doCmds that loops up to self.retrylimit iterations.
this allows us to move the retry logic outside of the _doCmds() to make it
easier for debugging in the future.
note that since cmdlist is a list of commands, they will all be retried if
one fails. this is necessary in particular for pushFile(), where we don't want
to accidentally send extra data if a failure occurs during data transmission.
'''
done = False
while self.retries < self.retrylimit: