author | David Anderson <danderson@mozilla.com> |
Thu, 12 Jul 2012 13:23:26 -0700 | |
changeset 106542 | 35ef899801bc41b0af7b694f3858ba3c225dbd8e |
parent 106541 | 1de2098ac6d98f2892882754b2c49e280b1cf399 (current diff) |
parent 99068 | f9499238bd4b82cb34b2ab2fd1aafde29ea3007e (diff) |
child 106543 | 3359300edfe70914966164f672d4e2007238959b |
push id | 23447 |
push user | danderson@mozilla.com |
push date | Tue, 11 Sep 2012 17:34:27 +0000 |
treeherder | mozilla-central@fdfaef738a00 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 16.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- 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: try: - self._doCmds(cmdlist, outputfile, timeout, newline) + self._doCmds(cmdlist, outputfile, timeout) return except AgentError, err: # re-raise error if it's fatal (i.e. the device got the command but # couldn't execute it). retry otherwise if err.fatal: raise err if self.debug >= 2: print err self.retries += 1 raise AgentError("unable to connect to %s after %s attempts" % (self.host, self.retrylimit)) - def runCmds(self, cmdlist, timeout = None, newline = True): + def runCmds(self, cmdlist, timeout = None): ''' similar to sendCmds, but just returns any output as a string instead of writing to a file. this is normally what you want to call to send a set of commands to the agent ''' outputfile = StringIO.StringIO() - self.sendCmds(cmdlist, outputfile, timeout, newline) + self.sendCmds(cmdlist, outputfile, timeout) outputfile.seek(0) return outputfile.read() - def _doCmds(self, cmdlist, outputfile, timeout, newline): + def _doCmds(self, cmdlist, outputfile, timeout): promptre = re.compile(self.prompt_regex + '$') shouldCloseSocket = False recvGuard = 1000 if not self._sock: try: if self.debug >= 1: print "reconnecting socket" @@ -173,59 +170,67 @@ class DeviceManagerSUT(DeviceManager): self._sock.connect((self.host, int(self.port))) self._sock.recv(1024) except socket.error, msg: self._sock.close() self._sock = None raise AgentError("unable to connect socket: "+str(msg)) for cmd in cmdlist: - if newline: cmd += '\r\n' + cmdline = '%s\r\n' % cmd['cmd'] try: - numbytes = self._sock.send(cmd) - if (numbytes != len(cmd)): - raise AgentError("ERROR: our cmd was %s bytes and we only sent %s" % (len(cmd), - numbytes)) - if (self.debug >= 4): print "send cmd: " + str(cmd) + sent = self._sock.send(cmdline) + if sent != len(cmdline): + raise AgentError("ERROR: our cmd was %s bytes and we " + "only sent %s" % (len(cmdline), sent)) + if cmd.get('data'): + sent = self._sock.send(cmd['data']) + if sent != len(cmd['data']): + raise AgentError("ERROR: we had %s bytes of data to send, but " + "only sent %s" % (len(cmd['data'], sent))) + + if (self.debug >= 4): print "sent cmd: " + str(cmd['cmd']) except socket.error, msg: self._sock.close() self._sock = None if self.debug >= 1: - print "Error sending data to socket. cmd="+str(cmd)+"; err="+str(msg) + print "Error sending data to socket. cmd="+str(cmd['cmd'])+"; err="+str(msg) return False # Check if the command should close the socket - shouldCloseSocket = self._shouldCmdCloseSocket(cmd) + shouldCloseSocket = self._shouldCmdCloseSocket(cmd['cmd']) # Handle responses from commands - if (self._cmdNeedsResponse(cmd)): + if (self._cmdNeedsResponse(cmd['cmd'])): found = False loopguard = 0 data = "" while (found == False and (loopguard < recvGuard)): temp = '' if (self.debug >= 4): print "recv'ing..." # Get our response try: temp = self._sock.recv(1024) if (self.debug >= 4): print "response: " + str(temp) except socket.error, msg: self._sock.close() self._sock = None - raise AgentError("Error receiving data from socket. cmd="+str(cmd)+"; err="+str(msg)) + raise AgentError("Error receiving data from socket. cmd="+str(cmd['cmd'])+"; err="+str(msg)) data += temp # If something goes wrong in the agent it will send back a string that - # starts with '##AGENT-ERROR##' - if self.agentErrorRE.match(data): - raise AgentError("Agent Error processing command: %s" % cmd, fatal=True) + # starts with '##AGENT-WARNING##' + errorMatch = self.agentErrorRE.match(data) + if errorMatch: + raise AgentError("Agent Error processing command '%s'; err='%s'" % + (cmd['cmd'], errorMatch.group(1)), fatal=True) for line in data.splitlines(): if promptre.match(line): found = True data = self._stripPrompt(data) break # periodically flush data to output file to make sure it doesn't get @@ -256,19 +261,19 @@ class DeviceManagerSUT(DeviceManager): # failure: None def shell(self, cmd, outputfile, env=None, cwd=None): cmdline = subprocess.list2cmdline(cmd) if env: cmdline = '%s %s' % (self.formatEnvString(env), cmdline) try: if cwd: - self.sendCmds(['execcwd %s %s' % (cwd, cmdline)], outputfile) + self.sendCmds([{ 'cmd': 'execcwd %s %s' % (cwd, cmdline) }], outputfile) else: - self.sendCmds(['exec su -c "%s"' % cmdline], outputfile) + self.sendCmds([{ 'cmd': 'exec su -c "%s"' % cmdline }], outputfile) except AgentError: return None # dig through the output to get the return code lastline = _pop_last_line(outputfile) if lastline: m = re.search('return code \[([0-9]+)\]', lastline) if m: @@ -301,19 +306,21 @@ class DeviceManagerSUT(DeviceManager): if (self.debug >= 3): print "sending: push " + destname filesize = os.path.getsize(localname) f = open(localname, 'rb') data = f.read() f.close() try: - retVal = self.runCmds(['push ' + destname + ' ' + str(filesize) + '\r\n', data], newline = False) - except AgentError: - retVal = False + retVal = self.runCmds([{ 'cmd': 'push ' + destname + ' ' + str(filesize), + 'data': data }]) + except AgentError, e: + print "error pushing file: %s" % e.msg + return False if (self.debug >= 3): print "push returned: " + str(retVal) validated = False if (retVal): retline = retVal.strip() if (retline == None): # Then we failed to get back a hash from agent, try manual validation @@ -338,17 +345,17 @@ class DeviceManagerSUT(DeviceManager): # returns: # success: directory name # failure: None def mkDir(self, name): if (self.dirExists(name)): return name else: try: - retVal = self.runCmds(['mkdr ' + name]) + retVal = self.runCmds([{ 'cmd': 'mkdr ' + name }]) except AgentError: retVal = None return retVal # make directory structure on the device # external function # returns: # success: directory structure that we created @@ -391,17 +398,17 @@ class DeviceManagerSUT(DeviceManager): # external function # returns: # success: True # failure: False def dirExists(self, dirname): match = ".*" + dirname.replace('^', '\^') + "$" dirre = re.compile(match) try: - data = self.runCmds(['cd ' + dirname, 'cwd']) + data = self.runCmds([ { 'cmd': 'cd ' + dirname }, { 'cmd': 'cwd' }]) except AgentError: return False found = False for d in data.splitlines(): if (dirre.match(d)): found = True @@ -427,59 +434,59 @@ class DeviceManagerSUT(DeviceManager): # returns: # success: array of filenames, ['file1', 'file2', ...] # failure: [] def listFiles(self, rootdir): rootdir = rootdir.rstrip('/') if (self.dirExists(rootdir) == False): return [] try: - data = self.runCmds(['cd ' + rootdir, 'ls']) + data = self.runCmds([{ 'cmd': 'cd ' + rootdir }, { 'cmd': 'ls' }]) except AgentError: return [] files = filter(lambda x: x, data.splitlines()) if len(files) == 1 and files[0] == '<empty>': # special case on the agent: empty directories return just the string "<empty>" return [] return files # external function # returns: # success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt" # failure: None def removeFile(self, filename): if (self.debug>= 2): print "removing file: " + filename try: - retVal = self.runCmds(['rm ' + filename]) + retVal = self.runCmds([{ 'cmd': 'rm ' + filename }]) except AgentError: return None return retVal # does a recursive delete of directory on the device: rm -Rf remoteDir # external function # returns: # success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt" # failure: None def removeDir(self, remoteDir): try: - retVal = self.runCmds(['rmdr ' + remoteDir]) + retVal = self.runCmds([{ 'cmd': 'rmdr ' + remoteDir }]) except AgentError: return None return retVal # external function # returns: # success: array of process tuples # failure: [] def getProcessList(self): try: - data = self.runCmds(['ps']) + data = self.runCmds([{ 'cmd': 'ps' }]) except AgentError: return [] files = [] for line in data.splitlines(): if line: pidproc = line.strip().split() if (len(pidproc) == 2): @@ -502,17 +509,17 @@ class DeviceManagerSUT(DeviceManager): if (self.debug >= 2): print "FIRE PROC: '" + appname + "'" if (self.processExist(appname) != None): print "WARNING: process %s appears to be running already\n" % appname