Merge fx-team to central, a=merge

This commit is contained in:
Wes Kocher 2015-10-20 14:53:07 -07:00
commit c337b1231d
67 changed files with 671 additions and 509 deletions

View File

@ -676,7 +676,7 @@
<hbox id="nav-bar-customization-target" flex="1">
<toolbaritem id="urlbar-container" flex="400" persist="width"
title="&locationItem.title;" removable="false"
removable="false"
class="chromeclass-location" overflows="false">
<toolbarbutton id="back-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
label="&backCmd.label;"
@ -799,16 +799,13 @@
<toolbarbutton id="urlbar-go-button"
class="chromeclass-toolbar-additional"
onclick="gURLBar.handleCommand(event);"
aria-label="&goEndCap.tooltip;"
tooltiptext="&goEndCap.tooltip;"/>
<toolbarbutton id="urlbar-reload-button"
class="chromeclass-toolbar-additional"
command="Browser:ReloadOrDuplicate"
onclick="checkForMiddleClick(this, event);"
aria-label="&reloadButton.tooltip;"
tooltiptext="&reloadButton.tooltip;"/>
<toolbarbutton id="urlbar-stop-button"
aria-label="&stopButton.tooltip;"
class="chromeclass-toolbar-additional"
command="Browser:Stop"
tooltiptext="&stopButton.tooltip;"/>

View File

@ -3,5 +3,7 @@ support-files =
file_dom_notifications.html
[browser_notification_open_settings.js]
[browser_notification_remove_permission.js]
skip-if = e10s
[browser_notification_tab_switching.js]
skip-if = buildapp == 'mulet' || e10s # Bug 1100662 - content access causing uncaught exception - Error: cannot ipc non-cpow object at chrome://mochitests/content/browser/browser/base/content/test/general/browser_notification_tab_switching.js:32 (or in RemoteAddonsChild.jsm)

View File

@ -0,0 +1,79 @@
"use strict";
var tab;
var notification;
var notificationURL = "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
var alertWindowClosed = false;
var permRemoved = false;
function test () {
waitForExplicitFinish();
let pm = Services.perms;
registerCleanupFunction(function() {
pm.remove(makeURI(notificationURL), "desktop-notification");
gBrowser.removeTab(tab);
window.restore();
});
pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION);
tab = gBrowser.addTab(notificationURL);
gBrowser.selectedTab = tab;
tab.linkedBrowser.addEventListener("load", onLoad, true);
}
function onLoad() {
tab.linkedBrowser.removeEventListener("load", onLoad, true);
let win = tab.linkedBrowser.contentWindow.wrappedJSObject;
notification = win.showNotification2();
notification.addEventListener("show", onAlertShowing);
}
function onAlertShowing() {
info("Notification alert showing");
notification.removeEventListener("show", onAlertShowing);
let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
if (!alertWindow) {
ok(true, "Notifications don't use XUL windows on all platforms.");
notification.close();
finish();
return;
}
ok(Services.perms.testExactPermission(makeURI(notificationURL), "desktop-notification"),
"Permission should exist prior to removal");
let disableForOriginMenuItem = alertWindow.document.getElementById("disableForOriginMenuItem");
is(disableForOriginMenuItem.localName, "menuitem", "menuitem found");
Services.obs.addObserver(permObserver, "perm-changed", false);
alertWindow.addEventListener("beforeunload", onAlertClosing);
disableForOriginMenuItem.click();
info("Clicked on disable-for-origin menuitem")
}
function permObserver(subject, topic, data) {
if (topic != "perm-changed") {
return;
}
let permission = subject.QueryInterface(Ci.nsIPermission);
is(permission.type, "desktop-notification", "desktop-notification permission changed");
is(data, "deleted", "desktop-notification permission deleted");
Services.obs.removeObserver(permObserver, "perm-changed");
permRemoved = true;
if (alertWindowClosed) {
finish();
}
}
function onAlertClosing(event) {
event.target.removeEventListener("beforeunload", onAlertClosing);
alertWindowClosed = true;
if (permRemoved) {
finish();
}
}

View File

@ -60,7 +60,7 @@ function onAlertShowing() {
let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
if (!alertWindow) {
todo(false, "Notifications don't use XUL windows on all platforms.");
ok(true, "Notifications don't use XUL windows on all platforms.");
notification.close();
newWindowOpenedFromTab.close();
finish();

View File

@ -218,8 +218,6 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY urlbar.toggleAutocomplete.label "Toggle the autocomplete popup">
<!ENTITY locationItem.title "Location">
<!ENTITY searchItem.title "Search">
<!-- Toolbar items -->

View File

@ -125,3 +125,8 @@
shown in the inspector contextual-menu for the item that lets users take
a screenshot of the currently selected node. -->
<!ENTITY inspectorScreenshotNode.label "Screenshot Node">
<!-- LOCALIZATION NOTE (inspectorDuplicateNode.label): This is the label
shown in the inspector contextual-menu for the item that lets users
duplicate the currently selected node. -->
<!ENTITY inspectorDuplicateNode.label "Duplicate Node">

View File

@ -893,7 +893,7 @@ toolbar .toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > :-moz-any(.toolbarb
transition: opacity 0.15s ease;
}
#navigator-toolbox:not(:hover) .urlbar-history-dropmarker {
#navigator-toolbox:not(:hover) #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
opacity: 0;
}

View File

@ -4,7 +4,7 @@
%filter substitution
%define toolbarHighlight rgba(255,255,255,.3)
%define toolbarHighlight rgba(255,255,255,.4)
%define fgTabTexture linear-gradient(transparent 2px, @toolbarHighlight@ 2px, @toolbarHighlight@)
%define fgTabTextureLWT @fgTabTexture@
%define fgTabBackgroundColor -moz-dialog

View File

@ -1697,7 +1697,7 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button {
transition: opacity 0.15s ease;
}
#navigator-toolbox:not(:hover) .urlbar-history-dropmarker {
#navigator-toolbox:not(:hover) #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
opacity: 0;
}

View File

@ -1410,7 +1410,7 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
transition: opacity 0.15s ease;
}
#navigator-toolbox:not(:hover) .urlbar-history-dropmarker {
#navigator-toolbox:not(:hover) #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
opacity: 0;
}

View File

@ -4,7 +4,7 @@
%filter substitution
%define toolbarHighlight rgba(255,255,255,.3)
%define toolbarHighlight rgba(255,255,255,.4)
%define fgTabTexture linear-gradient(transparent 2px, @toolbarHighlight@ 2px, @toolbarHighlight@)
%define fgTabBackgroundColor -moz-dialog
%define fgTabTextureLWT @fgTabTexture@

View File

@ -654,6 +654,9 @@ InspectorPanel.prototype = {
!this.selection.isPseudoElementNode();
let isEditableElement = isSelectionElement &&
!this.selection.isAnonymousNode();
let isDuplicatableElement = isSelectionElement &&
!this.selection.isAnonymousNode() &&
!this.selection.isRoot();
let isScreenshotable = isSelectionElement &&
this.canGetUniqueSelector &&
this.selection.nodeFront.isTreeDisplayed;
@ -683,6 +686,7 @@ InspectorPanel.prototype = {
// "Copy outer HTML", "Scroll Into View" & "Screenshot Node" as appropriate
let unique = this.panelDoc.getElementById("node-menu-copyuniqueselector");
let screenshot = this.panelDoc.getElementById("node-menu-screenshotnode");
let duplicateNode = this.panelDoc.getElementById("node-menu-duplicatenode");
let copyInnerHTML = this.panelDoc.getElementById("node-menu-copyinner");
let copyOuterHTML = this.panelDoc.getElementById("node-menu-copyouter");
let scrollIntoView = this.panelDoc.getElementById("node-menu-scrollnodeintoview");
@ -700,10 +704,20 @@ InspectorPanel.prototype = {
expandAll.removeAttribute("disabled");
}
this._target.actorHasMethod("domwalker", "duplicateNode").then(value => {
duplicateNode.hidden = !value;
});
this._target.actorHasMethod("domnode", "scrollIntoView").then(value => {
scrollIntoView.hidden = !value;
});
if (isDuplicatableElement) {
duplicateNode.removeAttribute("disabled");
}
else {
duplicateNode.setAttribute("disabled", "true");
}
if (isSelectionElement) {
unique.removeAttribute("disabled");
copyInnerHTML.removeAttribute("disabled");
@ -1177,6 +1191,20 @@ InspectorPanel.prototype = {
this.selection.nodeFront.scrollIntoView();
},
/**
* Duplicate the selected node
*/
duplicateNode: function() {
let selection = this.selection;
if (!selection.isElementNode() ||
selection.isRoot() ||
selection.isAnonymousNode() ||
selection.isPseudoElementNode()) {
return;
}
this.walker.duplicateNode(selection.nodeFront).catch(e => console.error(e));
},
/**
* Delete the selected node.
*/

View File

@ -103,6 +103,9 @@
<menuitem id="node-menu-screenshotnode"
label="&inspectorScreenshotNode.label;"
oncommand="inspector.screenshotNode()" />
<menuitem id="node-menu-duplicatenode"
label="&inspectorDuplicateNode.label;"
oncommand="inspector.duplicateNode()"/>
<menuitem id="node-menu-delete"
label="&inspectorHTMLDelete.label;"
accesskey="&inspectorHTMLDelete.accesskey;"

View File

@ -4,17 +4,14 @@ http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests for menuitem functionality that doesn't fit into any specific category
const TEST_URL = TEST_URL_ROOT + "doc_inspector_menu.html";
add_task(function* () {
let { inspector, toolbox, testActor } = yield openInspectorForURL(TEST_URL);
yield testShowDOMProperties();
yield testDuplicateNode();
yield testDeleteNode();
yield testDeleteRootNode();
yield testScrollIntoView();
function* testShowDOMProperties() {
info("Testing 'Show DOM Properties' menu item.");
let showDOMPropertiesNode = inspector.panelDoc.getElementById("node-menu-showdomproperties");
@ -29,20 +26,38 @@ add_task(function* () {
let webconsoleUI = toolbox.getPanel("webconsole").hud.ui;
let messagesAdded = webconsoleUI.once("new-messages");
yield messagesAdded;
info("Checking if 'inspect($0)' was evaluated");
ok(webconsoleUI.jsterm.history[0] === 'inspect($0)');
yield toolbox.toggleSplitConsole();
}
function* testDuplicateNode() {
info("Testing 'Duplicate Node' menu item for normal elements.");
yield selectNode(".duplicate", inspector);
is((yield testActor.getNumberOfElementMatches(".duplicate")), 1,
"There should initially be 1 .duplicate node");
let menuItem = inspector.panelDoc.getElementById("node-menu-duplicatenode");
ok(menuItem, "'Duplicate node' menu item should exist");
info("Triggering 'Duplicate Node' and waiting for inspector to update");
let updated = inspector.once("markupmutation");
dispatchCommandEvent(menuItem);
yield updated;
is((yield testActor.getNumberOfElementMatches(".duplicate")), 2,
"The duplicated node should be in the markup.");
let container = yield getContainerForSelector(".duplicate + .duplicate",
inspector);
ok(container, "A MarkupContainer should be created for the new node");
}
function* testDeleteNode() {
info("Testing 'Delete Node' menu item for normal elements.");
yield selectNode("#delete", inspector);
let deleteNode = inspector.panelDoc.getElementById("node-menu-delete");
ok(deleteNode, "the popup menu has a delete menu item");
let updated = inspector.once("inspector-updated");
info("Triggering 'Delete Node' and waiting for inspector to update");

View File

@ -15,6 +15,7 @@
</div>
<p data-id="copy">Paragraph for testing copy</p>
<p id="sensitivity">Paragraph for sensitivity</p>
<p class="duplicate">This will be duplicated</p>
<p id="delete">This has to be deleted</p>
<img id="copyimage" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVQYV2P4DwABAQEAWk1v8QAAAABJRU5ErkJggg==" />
<div id="hiddenElement" style="display: none;">

View File

@ -224,14 +224,14 @@ devtools.jar:
skin/themes/images/breadcrumbs-scrollbutton@2x.png (themes/images/breadcrumbs-scrollbutton@2x.png)
skin/themes/animationinspector.css (themes/animationinspector.css)
skin/themes/eyedropper.css (themes/eyedropper.css)
* skin/themes/canvasdebugger.css (themes/canvasdebugger.css)
skin/themes/canvasdebugger.css (themes/canvasdebugger.css)
skin/themes/debugger.css (themes/debugger.css)
* skin/themes/netmonitor.css (themes/netmonitor.css)
skin/themes/performance.css (themes/performance.css)
skin/themes/memory.css (themes/memory.css)
skin/themes/promisedebugger.css (themes/promisedebugger.css)
skin/themes/images/timeline-filter.svg (themes/images/timeline-filter.svg)
* skin/themes/scratchpad.css (themes/scratchpad.css)
skin/themes/scratchpad.css (themes/scratchpad.css)
skin/themes/shadereditor.css (themes/shadereditor.css)
skin/themes/storage.css (themes/storage.css)
* skin/themes/splitview.css (themes/splitview.css)

View File

@ -82,6 +82,21 @@ var TestActor = exports.TestActor = protocol.ActorClass({
}
return node;
},
/**
* Helper to get the number of elements matching a selector
* @param {string} CSS selector.
*/
getNumberOfElementMatches: protocol.method(function (selector,
root=this.content.document) {
return root.querySelectorAll(selector).length;
}, {
request: {
selector: Arg(0, "string"),
},
response: {
value: RetVal("number")
}
}),
/**
* Get a value for a given attribute name, on one of the elements of the box

View File

@ -2,14 +2,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
%filter substitution
%define darkCheckerboardBackground #000
%define lightCheckerboardBackground #fff
%define checkerboardCell rgba(128,128,128,0.2)
%define checkerboardPattern linear-gradient(45deg, @checkerboardCell@ 25%, transparent 25%, transparent 75%, @checkerboardCell@ 75%, @checkerboardCell@), linear-gradient(45deg, @checkerboardCell@ 25%, transparent 25%, transparent 75%, @checkerboardCell@ 75%, @checkerboardCell@)
%define gutterWidth 3em
%define gutterPaddingStart 22px
:root {
--gutter-width: 3em;
--gutter-padding-start: 22px;
--checkerboard-pattern: linear-gradient(45deg, rgba(128,128,128,0.2) 25%, transparent 25%, transparent 75%, rgba(128,128,128,0.2) 75%, rgba(128,128,128,0.2)),
linear-gradient(45deg, rgba(128,128,128,0.2) 25%, transparent 25%, transparent 75%, rgba(128,128,128,0.2) 75%, rgba(128,128,128,0.2));
}
/* Reload and waiting notices */
.notice-container {
@ -35,22 +33,9 @@
/* Snapshots pane */
#snapshots-pane > tabs {
-moz-border-end: 1px solid;
}
#snapshots-pane > tabs,
#snapshots-pane .devtools-toolbar {
-moz-border-end: 1px solid;
}
.theme-dark #snapshots-pane > tabs,
.theme-dark #snapshots-pane .devtools-toolbar {
-moz-border-end-color: black; /* Match the splitter color. */
}
.theme-light #snapshots-pane > tabs,
.theme-light #snapshots-pane .devtools-toolbar {
-moz-border-end-color: #aaa; /* Match the splitter color. */
-moz-border-end: 1px solid var(--theme-splitter-color);
}
#record-snapshot {
@ -65,7 +50,7 @@
.snapshot-item-thumbnail {
image-rendering: -moz-crisp-edges;
background-image: @checkerboardPattern@;
background-image: var(--checkerboard-pattern);
background-size: 12px 12px, 12px 12px;
background-position: 0px 0px, 6px 6px;
background-repeat: repeat, repeat;
@ -75,12 +60,8 @@
transform: scaleY(-1);
}
.theme-dark .snapshot-item-thumbnail {
background-color: @darkCheckerboardBackground@;
}
.theme-light .snapshot-item-thumbnail {
background-color: @lightCheckerboardBackground@;
.snapshot-item-thumbnail {
background-color: var(--theme-body-background);
}
.snapshot-item-details {
@ -234,9 +215,9 @@
}
.call-item-gutter {
width: calc(@gutterWidth@ + @gutterPaddingStart@);
-moz-padding-start: @gutterPaddingStart@;
-moz-padding-end: 4px;
width: calc(var(--gutter-width) + var(--gutter-padding-start));
padding-inline-start: var(--gutter-padding-start);
padding-inline-end: 4px;
padding-top: 2px;
padding-bottom: 2px;
-moz-border-end: 1px solid;
@ -300,7 +281,7 @@
}
.call-item-stack {
-moz-padding-start: calc(@gutterWidth@ + @gutterPaddingStart@);
-moz-padding-start: calc(var(--gutter-width) + var(--gutter-padding-start));
padding-bottom: 10px;
}
@ -345,20 +326,13 @@
/* Rendering preview */
#screenshot-container {
background-image: @checkerboardPattern@;
background-color: var(--theme-body-background);
background-image: var(--checkerboard-pattern);
background-size: 30px 30px, 30px 30px;
background-position: 0px 0px, 15px 15px;
background-repeat: repeat, repeat;
}
.theme-dark #screenshot-container {
background-color: @darkCheckerboardBackground@;
}
.theme-light #screenshot-container {
background-color: @lightCheckerboardBackground@;
}
@media (min-width: 701px) {
#screenshot-container {
width: 30vw;
@ -403,22 +377,22 @@
/* Snapshot filmstrip */
#snapshot-filmstrip {
border-top: 1px solid var(--theme-splitter-color);
overflow: hidden;
}
.theme-dark #snapshot-filmstrip {
border-top: 1px solid #000;
color: var(--theme-selection-color);
}
.theme-light #snapshot-filmstrip {
border-top: 1px solid #aaa;
color: var(--theme-body-color-alt);
}
.filmstrip-thumbnail {
image-rendering: -moz-crisp-edges;
background-image: @checkerboardPattern@;
background-color: var(--theme-body-background);
background-image: var(--checkerboard-pattern);
background-size: 12px 12px, 12px 12px;
background-position: 0px -1px, 6px 5px;
background-repeat: repeat, repeat;
@ -426,6 +400,7 @@
cursor: pointer;
padding-top: 1px;
padding-bottom: 1px;
border-inline-end: 1px solid var(--theme-splitter-color);
transition: opacity 0.1s ease-in-out;
}
@ -433,18 +408,6 @@
transform: scaleY(-1);
}
.theme-dark .filmstrip-thumbnail {
background-color: @darkCheckerboardBackground@;
}
.theme-light .filmstrip-thumbnail {
background-color: @lightCheckerboardBackground@;
}
.filmstrip-thumbnail {
-moz-border-end: 1px solid var(--theme-splitter-color)
}
#snapshot-filmstrip > .filmstrip-thumbnail:hover,
#snapshot-filmstrip:not(:hover) > .filmstrip-thumbnail[highlighted] {
border: 1px solid var(--theme-highlight-blue);

View File

@ -1,8 +1,6 @@
%if 0
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%endif
#scratchpad-sidebar > tabs {
height: 0;

View File

@ -67,14 +67,7 @@
.stylesheet-sidebar {
max-width: 400px;
min-width: 100px;
}
.theme-light .stylesheet-sidebar {
border-color: #aaa; /* Splitters */
}
.theme-dark .stylesheet-sidebar {
border-color: #000; /* Splitters */
border-color: var(--theme-splitter-color);
}
.theme-light .media-rule-label {

View File

@ -563,47 +563,21 @@
}
.devtools-sidebar-tabs tabs > tab:first-child {
-moz-border-start-width: 0;
border-inline-start-width: 0;
}
.theme-dark .devtools-sidebar-tabs tabs > tab:hover {
background: hsla(206,37%,4%,.2);
.devtools-sidebar-tabs tabs > tab:hover {
background: rgba(0, 0, 0, 0.12);
}
.theme-dark .devtools-sidebar-tabs tabs > tab:hover:active {
background: hsla(206,37%,4%,.4);
.devtools-sidebar-tabs tabs > tab:hover:active {
background: rgba(0, 0, 0, 0.2);
}
.theme-dark .devtools-sidebar-tabs tabs > tab[selected] + tab:hover {
background: hsla(206,37%,4%,.2);
}
.theme-dark .devtools-sidebar-tabs tabs > tab[selected] + tab:hover:active {
background: hsla(206,37%,4%,.4);
}
.theme-dark .devtools-sidebar-tabs tabs > tab[selected],
.theme-dark .devtools-sidebar-tabs tabs > tab[selected]:hover:active {
.devtools-sidebar-tabs tabs > tab[selected],
.devtools-sidebar-tabs tabs > tab[selected]:hover:active {
color: var(--theme-selection-color);
background: #1d4f73;
}
.theme-light .devtools-sidebar-tabs tabs > tab:hover {
background: #ddd;
}
.theme-light .devtools-sidebar-tabs tabs > tab:hover:active {
background: #ddd;
}
.theme-light .devtools-sidebar-tabs tabs > tab[selected] + tab:hover {
background: #ddd;
}
.theme-light .devtools-sidebar-tabs tabs > tab[selected],
.theme-light .devtools-sidebar-tabs tabs > tab[selected]:hover:active {
color: var(--theme-selection-color);
background: #4c9ed9;
background: var(--theme-selection-background);
}
/* Toolbox - moved from toolbox.css.

View File

@ -30,10 +30,10 @@ svg {
}
.theme-dark .edgePath path {
stroke: #b6babf; /* Grey foreground text */
stroke: var(--theme-body-color-alt);
}
.theme-light .edgePath path {
stroke: #aaaaaa; /* Splitters */
stroke: var(--theme-splitter-color);
}
/* AudioParam connection edges */
@ -42,27 +42,21 @@ g.edgePath.param-connection {
}
.theme-dark .edgePath.param-connection path {
stroke: #b6babf; /* Grey foreground text */
stroke: var(--theme-body-color-alt);
}
.theme-light .edgePath.param-connection path {
stroke: #aaaaaa; /* Splitters */
stroke: var(--theme-splitter-color);
}
/* Labels in AudioParam connection should have background that match
* the main background so there's whitespace around the label, on top of the
* dotted lines. */
.theme-dark g.edgeLabel rect {
fill: #14171a;
g.edgeLabel rect {
fill: var(--theme-body-background);
}
.theme-light g.edgeLabel rect {
fill: #fcfcfc; /* Background - Editor */
}
.theme-dark g.edgeLabel tspan {
g.edgeLabel tspan {
fill: var(--theme-body-color-alt);
}
.theme-light g.edgeLabel tspan {
fill: #585959; /* Grey foreground text */
}
/* Audio Nodes */
.nodes rect {
@ -219,11 +213,8 @@ text {
background-color: transparent;
}
.theme-dark #audio-node-toolbar toolbarbutton[checked] {
background-color: #1d4f73; /* Select Highlight Blue */
}
.theme-light #audio-node-toolbar toolbarbutton[checked] {
background-color: #4c9ed9; /* Select Highlight Blue */
#audio-node-toolbar toolbarbutton[checked] {
background-color: var(--theme-selection-background);
}
/* don't invert checked buttons so we can have white icons on light theme */

View File

@ -26,7 +26,7 @@ a {
.message > .prefix,
.message > .timestamp {
flex: none;
color: GrayText;
color: var(--theme-comment);
margin: 3px 6px 0 0;
}
@ -131,11 +131,6 @@ a {
margin-top: 0;
}
.jsterm-input-container {
border-top-width: 1px;
border-top-style: solid;
}
#output-wrapper {
direction: ltr;
overflow: auto;
@ -253,11 +248,11 @@ a {
}
.message[category=network].mixed-content .url {
color: #FF0000;
color: var(--theme-highlight-red);
}
.message .learn-more-link {
color: -moz-nativehyperlinktext;
color: var(--theme-highlight-blue);
margin: 0 6px;
}
@ -360,6 +355,18 @@ a {
}
/* JSTerm Styles */
.jsterm-input-container {
background-color: var(--theme-tab-toolbar-background);
border-top: 1px solid var(--theme-splitter-color);
}
.theme-light .jsterm-input-container {
/* For light theme use a white background for the input - it looks better
than off-white */
background-color: #fff;
border-top-color: #e0e0e0;
}
.jsterm-input-node,
.jsterm-complete-node {
border: none;
@ -368,10 +375,15 @@ a {
background-color: transparent;
}
.jsterm-complete-node {
color: var(--theme-comment);
}
.jsterm-input-node {
background-image: -moz-image-rect(url("chrome://devtools/skin/themes/images/commandline-icon.png"), 0, 32, 16, 16);
background-repeat: no-repeat;
background-size: 16px 16px;
color: var(--theme-content-color1);
}
@media (min-resolution: 1.1dppx) {
@ -398,7 +410,7 @@ a {
margin-top: 5px;
margin-bottom: 15px;
-moz-margin-end: 15px;
border: 1px solid rgba(128, 128, 128, .5);
border: 1px solid var(--theme-splitter-color);
border-radius: 3px;
}
@ -442,6 +454,11 @@ a {
.navigation-marker .url {
-moz-padding-end: 9px;
text-decoration: none;
background: var(--theme-body-background);
}
.theme-light .navigation-marker .url {
background: #fff;
}
.stacktrace {
@ -451,7 +468,7 @@ a {
margin: 5px 0 0 0;
max-height: 10em;
overflow-y: auto;
border: 1px solid rgb(200,200,200);
border: 1px solid var(--theme-splitter-color);
border-radius: 3px;
}
@ -514,49 +531,6 @@ a {
background-position: -16px 0;
}
.jsterm-input-container {
background-color: var(--theme-tab-toolbar-background);
border-color: var(--theme-body-background);
}
.jsterm-input-node {
color: var(--theme-content-color1);
}
.jsterm-complete-node {
color: var(--theme-comment);
}
.navigation-marker .url {
background: var(--theme-body-background);
}
.theme-dark .inlined-variables-view iframe {
border-color: #333;
}
.theme-dark .stacktrace {
border-color: #333;
}
.theme-light .jsterm-input-container {
/* For light theme use a white background for the input - it looks better
than off-white */
background-color: #fff;
border-color: ThreeDShadow;
}
.theme-light .navigation-marker .url {
background: #fff;
}
.theme-light .inlined-variables-view iframe {
border-color: #ccc;
}
.theme-light .stacktrace {
border-color: #ccc;
}
@media (max-width: 500px) {
.message > .timestamp {
display: none;

View File

@ -2592,6 +2592,21 @@ var WalkerActor = protocol.ActorClass({
response: RetVal("disconnectedNodeArray")
}),
/**
* Duplicate a specified node
*
* @param {NodeActor} node The node to duplicate.
*/
duplicateNode: method(function({rawNode}) {
let clonedNode = rawNode.cloneNode(true);
rawNode.parentNode.insertBefore(clonedNode, rawNode.nextSibling);
}, {
request: {
node: Arg(0, "domnode")
},
response: {}
}),
/**
* Test whether a node is a document or a document element.
*

View File

@ -57,6 +57,7 @@ skip-if = buildapp == 'mulet'
[test_inspector-changeattrs.html]
[test_inspector-changevalue.html]
[test_inspector-dead-nodes.html]
[test_inspector-duplicate-node.html]
[test_inspector_getImageData.html]
skip-if = buildapp == 'mulet'
[test_inspector_getImageDataFromURL.html]

View File

@ -80,12 +80,11 @@
<select multiple><option>one</option><option>two</option></select>
<div id="pseudo"><span>middle</span></div>
<div id="pseudo-empty"></div>
<div id="shadow">light dom</div>
<object>
<div id="1"></div>
</object>
<div class="node-to-duplicate"></div>
<div id="scroll-into-view" style="margin-top: 1000px;">scroll</div>
</body>
</html>

View File

@ -0,0 +1,75 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1208864
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1208864</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript;version=1.8" src="inspector-helpers.js"></script>
<script type="application/javascript;version=1.8">
const inspector = require("devtools/server/actors/inspector");
window.onload = function() {
SimpleTest.waitForExplicitFinish();
runNextTest();
}
var gInspectee = null;
var gClient = null;
var gWalker = null;
function assertOwnership() {
assertOwnershipTrees(gWalker);
}
addTest(function setup() {
let url = document.getElementById("inspectorContent").href;
attachURL(url, function(err, client, tab, doc) {
gInspectee = doc;
let {InspectorFront} = require("devtools/server/actors/inspector");
let inspector = InspectorFront(client, tab);
promiseDone(inspector.getWalker().then(walker => {
ok(walker, "getWalker() should return an actor.");
gClient = client;
gWalker = walker;
}).then(runNextTest));
});
});
addTest(Task.async(function* testDuplicateNode() {
let className = ".node-to-duplicate";
let matches = yield gWalker.querySelectorAll(gWalker.rootNode, className);
is(matches.length, 1, "There should initially be one node to duplicate.");
let nodeFront = yield gWalker.querySelector(gWalker.rootNode, className);
yield gWalker.duplicateNode(nodeFront);
matches = yield gWalker.querySelectorAll(gWalker.rootNode, className);
is(matches.length, 2, "The node should now be duplicated.");
runNextTest();
}));
addTest(function cleanup() {
delete gWalker;
delete gInspectee;
delete gClient;
runNextTest();
});
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1208864">Mozilla Bug 1208864</a>
<a id="inspectorContent" target="_blank" href="inspector-traversal-data.html">Test Document</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -458,6 +458,25 @@ exports.dbg_assert = function dbg_assert(cond, e) {
}
};
exports.defineLazyGetter(this, "AppConstants", () => {
const scope = {};
Cu.import("resource://gre/modules/AppConstants.jsm", scope);
return scope.AppConstants;
});
/**
* No operation. The empty function.
*/
exports.noop = function () { };
function reallyAssert(condition, message) {
if (!condition) {
const err = new Error("Assertion failure: " + message);
exports.reportException("DevToolsUtils.assert", err);
throw err;
}
}
/**
* DevToolsUtils.assert(condition, message)
*
@ -477,23 +496,11 @@ exports.dbg_assert = function dbg_assert(cond, e) {
* This is an improvement over `dbg_assert`, which doesn't actually cause any
* fatal behavior, and is therefore much easier to accidentally ignore.
*/
exports.defineLazyGetter(exports, "assert", () => {
function noop(condition, msg) { }
function assert(condition, message) {
if (!condition) {
const err = new Error("Assertion failure: " + message);
exports.reportException("DevToolsUtils.assert", err);
throw err;
}
}
const scope = {};
Cu.import("resource://gre/modules/AppConstants.jsm", scope);
const { DEBUG, DEBUG_JS_MODULES } = scope.AppConstants;
return (DEBUG || DEBUG_JS_MODULES || exports.testing) ? assert : noop;
});
Object.defineProperty(exports, "assert", {
get: () => (AppConstants.DEBUG || AppConstants.DEBUG_JS_MODULES || this.testing)
? reallyAssert
: exports.noop,
})
/**
* Defines a getter on a specified object for a module. The module will not

View File

@ -10,6 +10,7 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/devtools/DeserializedNode.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/Nullable.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/Maybe.h"
#include "mozilla/RefCounted.h"
@ -139,6 +140,15 @@ public:
void TakeCensus(JSContext* cx, JS::HandleObject options,
JS::MutableHandleValue rval, ErrorResult& rv);
dom::Nullable<uint64_t> GetCreationTime() {
static const uint64_t maxTime = uint64_t(1) << 53;
if (timestamp.isSome() && timestamp.ref() <= maxTime) {
return dom::Nullable<uint64_t>(timestamp.ref());
}
return dom::Nullable<uint64_t>();
}
};
// A `CoreDumpWriter` is given the data we wish to save in a core dump and

View File

@ -0,0 +1,29 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// HeapSnapshot.prototype.creationTime returns the expected time.
function waitForTenMilliseconds() {
const start = Date.now();
while (Date.now() - start < 10) ;
}
function run_test() {
const start = Date.now() * 1000;
do_print("start = " + start);
// Because Date.now() is less precise than the snapshot's time stamp, give it
// a little bit of head room.
waitForTenMilliseconds();
const path = ChromeUtils.saveHeapSnapshot({ runtime: true });
waitForTenMilliseconds();
const end = Date.now() * 1000;
do_print("end = " + end);
const snapshot = ChromeUtils.readHeapSnapshot(path);
do_print("snapshot.creationTime = " + snapshot.creationTime);
ok(snapshot.creationTime >= start);
ok(snapshot.creationTime <= end);
}

View File

@ -25,6 +25,7 @@ support-files =
[test_HeapAnalyses_takeCensus_03.js]
[test_HeapAnalyses_takeCensus_04.js]
[test_HeapAnalyses_takeCensus_05.js]
[test_HeapSnapshot_creationTime_01.js]
[test_HeapSnapshot_takeCensus_01.js]
[test_HeapSnapshot_takeCensus_02.js]
[test_HeapSnapshot_takeCensus_03.js]

View File

@ -9,6 +9,11 @@ const DevToolsUtils = require("devtools/shared/DevToolsUtils");
// Register a console listener, so console messages don't just disappear
// into the ether.
// If for whatever reason the test needs to post console errors that aren't
// failures, set this to true.
var ALLOW_CONSOLE_ERRORS = false;
var errorCount = 0;
var listener = {
observe: function (aMessage) {
@ -35,7 +40,10 @@ var listener = {
while (DebuggerServer.xpcInspector.eventLoopNestLevel > 0) {
DebuggerServer.xpcInspector.exitNestedEventLoop();
}
do_throw("head_dbg.js got console message: " + string + "\n");
if (!ALLOW_CONSOLE_ERRORS) {
do_throw("head_devtools.js got console message: " + string + "\n");
}
}
};

View File

@ -0,0 +1,36 @@
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test DevToolsUtils.assert
ALLOW_CONSOLE_ERRORS = true;
function run_test() {
// Enable assertions.
DevToolsUtils.testing = true;
const { assert } = DevToolsUtils;
equal(typeof assert, "function");
try {
assert(true, "this assertion should not fail");
} catch (e) {
// If you catch assertion failures in practice, I will hunt you down. I get
// email notifications every time it happens.
ok(false, "Should not get an error for an assertion that should not fail. Got "
+ DevToolsUtils.safeErrorString(e));
}
let assertionFailed = false;
try {
assert(false, "this assertion should fail");
} catch (e) {
ok(e.message.startsWith("Assertion failure:"),
"Should be an assertion failure error");
assertionFailed = true;
}
ok(assertionFailed,
"The assertion should have failed, which should throw an error when assertions are enabled.");
}

View File

@ -6,6 +6,7 @@ skip-if = toolkit == 'android' || toolkit == 'gonk'
support-files =
exposeLoader.js
[test_assert.js]
[test_fetch-chrome.js]
[test_fetch-file.js]
[test_fetch-http.js]

View File

@ -9,6 +9,12 @@
*/
[ChromeOnly, Exposed=(Window,System,Worker)]
interface HeapSnapshot {
/**
* A time stamp of when the heap snapshot was taken, if available. Units are
* microseconds since midnight (00:00:00) 1 January 1970 UTC.
*/
readonly attribute unsigned long long? creationTime;
/**
* Take a census of the heap snapshot.
*

View File

@ -463,7 +463,9 @@ $(abspath $(DIST)/fennec/$(OMNIJAR_NAME)): FORCE
$(RM) $(DIST)/fennec/$(notdir $(OMNIJAR_NAME))
# Targets built very early during a Gradle build.
gradle-targets: .aapt.deps
gradle-targets: $(foreach f,$(constants_PP_JAVAFILES),$(f))
gradle-targets: $(abspath AndroidManifest.xml)
gradle-targets: $(ANDROID_GENERATED_RESFILES)
gradle-omnijar: $(abspath $(DIST)/fennec/$(OMNIJAR_NAME))

View File

@ -817,6 +817,7 @@ ANDROID_RES_DIRS += [
]
ANDROID_GENERATED_RESFILES += [
'res/raw/browsersearch.json',
'res/raw/suggestedsites.json',
'res/values/strings.xml',
]

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<org.mozilla.gecko.tabs.TabPanelBackButton xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:gecko="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_back"
android:layout_width="@dimen/tabs_panel_button_width"
android:layout_height="match_parent"
android:minWidth="@dimen/tabs_panel_button_width"
android:src="@drawable/tabs_panel_nav_back"
android:contentDescription="@string/back"
android:background="@drawable/action_bar_button_inverse"
gecko:dividerVerticalPadding="@dimen/tab_panel_divider_vertical_padding"
gecko:rightDivider="@drawable/tab_indicator_divider"/>

View File

@ -18,10 +18,16 @@
android:layout_height="@dimen/browser_toolbar_height"
android:background="@color/text_and_tabs_tray_grey">
<ViewStub android:id="@+id/nav_back_stub"
android:layout="@layout/tabs_panel_back_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"/>
<org.mozilla.gecko.tabs.TabPanelBackButton
android:id="@+id/nav_back"
android:layout_width="@dimen/tabs_panel_button_width"
android:layout_height="match_parent"
android:minWidth="@dimen/tabs_panel_button_width"
android:src="@drawable/tabs_panel_nav_back"
android:contentDescription="@string/back"
android:background="@drawable/action_bar_button_inverse"
gecko:dividerVerticalPadding="@dimen/tab_panel_divider_vertical_padding"
gecko:rightDivider="@drawable/tab_indicator_divider"/>
<org.mozilla.gecko.widget.IconTabWidget android:id="@+id/tab_widget"
android:layout_width="wrap_content"

View File

@ -96,9 +96,7 @@ public class TabsLayoutItemView extends LinearLayout
mCloseButton = (ImageView) findViewById(R.id.close);
mThumbnailWrapper = (TabThumbnailWrapper) findViewById(R.id.wrapper);
if (HardwareUtils.isTablet() || AppConstants.NIGHTLY_BUILD) {
growCloseButtonHitArea();
}
growCloseButtonHitArea();
}
private void growCloseButtonHitArea() {

View File

@ -164,16 +164,13 @@ public class TabsPanel extends LinearLayout
}
});
if (AppConstants.NIGHTLY_BUILD || HardwareUtils.isTablet()) {
ViewStub backButtonStub = (ViewStub) findViewById(R.id.nav_back_stub);
mNavBackButton = (ImageButton) backButtonStub.inflate( );
mNavBackButton.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View view) {
mActivity.onBackPressed();
}
});
}
mNavBackButton = (ImageButton) findViewById(R.id.nav_back);
mNavBackButton.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View view) {
mActivity.onBackPressed();
}
});
}
public void showMenu() {
@ -249,39 +246,12 @@ public class TabsPanel extends LinearLayout
}
private static int getTabContainerHeight(TabsLayoutContainer tabsContainer) {
Resources resources = tabsContainer.getContext().getResources();
final Resources resources = tabsContainer.getContext().getResources();
int screenHeight = resources.getDisplayMetrics().heightPixels;
int actionBarHeight = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height);
if (HardwareUtils.isTablet() || AppConstants.NIGHTLY_BUILD) {
return screenHeight - actionBarHeight;
}
PanelView panelView = tabsContainer.getCurrentPanelView();
if (panelView != null && !panelView.shouldExpand()) {
// This allows us to accommodate varying height tab previews across different devices.
// We should be able to remove once we remove the list view and remove the chrome again
return resources.getDimensionPixelSize(R.dimen.tab_thumbnail_height)
+ resources.getDimensionPixelSize(R.dimen.tab_title_height)
+ 2 * (resources.getDimensionPixelSize(R.dimen.tab_highlight_stroke_width)
+ resources.getDimensionPixelSize(R.dimen.tab_vertical_padding)
+ resources.getDimensionPixelSize(R.dimen.tab_thumbnail_padding)
+ resources.getDimensionPixelSize(R.dimen.tab_thumbnail_margin));
}
Rect windowRect = new Rect();
tabsContainer.getWindowVisibleDisplayFrame(windowRect);
int windowHeight = windowRect.bottom - windowRect.top;
// The web content area should have at least 1.5x the height of the action bar.
// The tabs panel shouldn't take less than 50% of the screen height and can take
// up to 80% of the window height.
return (int) Math.max(screenHeight * 0.5f,
Math.min(windowHeight - 2.5f * actionBarHeight, windowHeight * 0.8f) - actionBarHeight);
final int screenHeight = resources.getDisplayMetrics().heightPixels;
final int actionBarHeight = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height);
return screenHeight - actionBarHeight;
}
@Override

View File

@ -5,7 +5,6 @@
package org.mozilla.gecko.tabs;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.R;
import org.mozilla.gecko.ThumbnailHelper;
import org.mozilla.gecko.widget.CropImageView;
@ -35,11 +34,7 @@ public class TabsPanelThumbnailView extends CropImageView {
@Override
protected float getAspectRatio() {
if (AppConstants.NIGHTLY_BUILD) {
return ThumbnailHelper.TABS_PANEL_THUMBNAIL_ASPECT_RATIO;
} else {
return ThumbnailHelper.TOP_SITES_THUMBNAIL_ASPECT_RATIO;
}
return ThumbnailHelper.TABS_PANEL_THUMBNAIL_ASPECT_RATIO;
}
@Override

View File

@ -1318,6 +1318,7 @@ var BrowserApp = {
* @return the tab with the given URL, or null if no such tab exists
*/
getTabWithURL: function getTabWithURL(aURL, aOptions) {
aOptions = aOptions || {};
let uri = Services.io.newURI(aURL, null, null);
for (let i = 0; i < this._tabs.length; ++i) {
let tab = this._tabs[i];

View File

@ -7,6 +7,9 @@ android {
defaultConfig {
targetSdkVersion 22
minSdkVersion 9
applicationId mozconfig.substs.ANDROID_PACKAGE_NAME
testApplicationId 'org.mozilla.roboexample.test'
testInstrumentationRunner 'org.mozilla.gecko.FennecInstrumentationTestRunner'
}
compileOptions {
@ -25,13 +28,13 @@ android {
}
}
defaultConfig {
testApplicationId 'org.mozilla.roboexample.test'
testInstrumentationRunner 'org.mozilla.gecko.FennecInstrumentationTestRunner'
}
sourceSets {
main {
manifest.srcFile "${topobjdir}/mobile/android/base/AndroidManifest.xml"
}
androidTest {
manifest.srcFile "${topobjdir}/build/mobile/robocop/AndroidManifest.xml"
java {
srcDir "src/robocop_harness"
srcDir "src/robocop"

View File

@ -46,11 +46,18 @@ android {
srcDir 'src/webrtc_video_render'
}
// Adjust helpers are included in the preprocessed_code project.
exclude 'org/mozilla/gecko/adjust/**'
if (mozconfig.substs.MOZ_INSTALL_TRACKING) {
exclude 'org/mozilla/gecko/adjust/StubAdjustHelper.java'
} else {
exclude 'org/mozilla/gecko/adjust/AdjustHelper.java'
}
srcDir "${project.buildDir}/generated/source/preprocessed_code" // See syncPreprocessedCode.
}
res {
srcDir "src/branding/res"
srcDir "${project.buildDir}/generated/source/preprocessed_resources" // See syncPreprocessedResources.
if (mozconfig.substs.MOZ_CRASHREPORTER) {
srcDir "src/crashreporter/res"
}
@ -69,6 +76,22 @@ android {
}
}
task syncPreprocessedCode(type: Sync, dependsOn: rootProject.generateCodeAndResources) {
into("${project.buildDir}/generated/source/preprocessed_code")
from("${topobjdir}/mobile/android/base/generated/preprocessed")
}
task syncPreprocessedResources(type: Sync, dependsOn: rootProject.generateCodeAndResources) {
into("${project.buildDir}/generated/source/preprocessed_resources")
from("${topobjdir}/mobile/android/base/res")
}
android.libraryVariants.all { variant ->
variant.preBuild.dependsOn syncPreprocessedCode
variant.preBuild.dependsOn syncPreprocessedResources
}
dependencies {
compile 'com.android.support:support-v4:23.0.1'
compile 'com.android.support:appcompat-v7:23.0.1'
@ -81,11 +104,12 @@ dependencies {
compile 'com.google.android.gms:play-services-cast:8.1.0'
}
compile project(':branding')
compile project(':preprocessed_code')
compile project(':preprocessed_resources')
compile project(':thirdparty')
if (mozconfig.substs.MOZ_INSTALL_TRACKING) {
compile project(':thirdparty_adjust_sdk')
}
testCompile 'junit:junit:4.12'
testCompile 'org.robolectric:robolectric:3.0'
testCompile 'org.simpleframework:simple-http:4.1.13'

View File

@ -1,4 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mozilla.gecko.branding">
</manifest>

View File

@ -1,20 +0,0 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
targetSdkVersion 22
minSdkVersion 9
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
lintOptions {
abortOnError false
}
}

View File

@ -82,10 +82,10 @@ afterEvaluate {
return
}
android.applicationVariants.all {
checkManifest.dependsOn rootProject.generateCodeAndResources
preBuild.dependsOn rootProject.generateCodeAndResources
}
android.libraryVariants.all {
checkManifest.dependsOn rootProject.generateCodeAndResources
preBuild.dependsOn rootProject.generateCodeAndResources
}
}
}
@ -97,3 +97,6 @@ idea {
languageLevel = '1.7'
}
}
task wrapper(type: Wrapper) {
}

View File

@ -1,6 +1,6 @@
#Sun Dec 21 20:16:49 PST 2014
#Sun Oct 18 17:00:46 PDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-2.7-bin.zip

View File

@ -42,11 +42,6 @@ case "`uname`" in
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
@ -114,6 +109,7 @@ fi
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`

View File

@ -1,4 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mozilla.gecko.preprocessed_code">
</manifest>

View File

@ -1,53 +0,0 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
targetSdkVersion 22
minSdkVersion 9
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
lintOptions {
abortOnError false
}
sourceSets {
main {
java {
srcDir "${project.buildDir}/generated/source/java"
srcDir 'src/adjust/java'
if (mozconfig.substs.MOZ_INSTALL_TRACKING) {
exclude 'org/mozilla/gecko/adjust/StubAdjustHelper.java'
} else {
exclude 'org/mozilla/gecko/adjust/AdjustHelper.java'
}
}
}
}
}
task syncGeneratedSources(type: Sync) {
into("${project.buildDir}/generated/source/java")
from("${topobjdir}/mobile/android/base/generated/preprocessed")
}
android.libraryVariants.all { variant ->
// variant does not expose its generate sources task.
def name = variant.buildType.name
def generateSourcesTask = tasks.findByName("generate${name.capitalize()}Sources")
generateSourcesTask.dependsOn syncGeneratedSources
}
dependencies {
if (mozconfig.substs.MOZ_INSTALL_TRACKING) {
compile project(':thirdparty_adjust_sdk')
}
}

View File

@ -1,4 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mozilla.gecko.preprocessed_resources">
</manifest>

View File

@ -1,44 +0,0 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
targetSdkVersion 22
minSdkVersion 9
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
lintOptions {
abortOnError false
}
sourceSets {
main {
res {
srcDir "${project.buildDir}/generated/source/preprocessed_resources"
}
}
}
}
task syncPreprocessedResources(type: Sync) {
into("${project.buildDir}/generated/source/preprocessed_resources")
from("${topobjdir}/mobile/android/base/res")
}
android.libraryVariants.all { variant ->
// variant does not expose its generate debug res values task.
def name = variant.buildType.name
def generateResValuesTask = tasks.findByName("generate${name.capitalize()}ResValues")
generateResValuesTask.dependsOn syncPreprocessedResources
}
dependencies {
compile project(':branding')
}

View File

@ -25,19 +25,13 @@ def json = slurper.parseText(standardOutput.toString())
include ':app'
include ':base'
include ':branding'
include ':omnijar'
include ':preprocessed_code'
include ':preprocessed_resources'
include ':thirdparty'
def gradleRoot = new File("${json.topobjdir}/mobile/android/gradle")
project(':app').projectDir = new File(gradleRoot, 'app')
project(':base').projectDir = new File(gradleRoot, 'base')
project(':branding').projectDir = new File(gradleRoot, 'branding')
project(':omnijar').projectDir = new File(gradleRoot, 'omnijar')
project(':preprocessed_code').projectDir = new File(gradleRoot, 'preprocessed_code')
project(':preprocessed_resources').projectDir = new File(gradleRoot, 'preprocessed_resources')
project(':thirdparty').projectDir = new File(gradleRoot, 'thirdparty')
if (json.substs.MOZ_INSTALL_TRACKING) {

View File

@ -80,9 +80,6 @@ class MachCommands(MachCommandBase):
def srcdir(dst, src):
m.add_symlink(os.path.join(self.topsrcdir, src), dst)
def objdir(dst, src):
m.add_symlink(os.path.join(self.topobjdir, src), dst)
srcdir('build.gradle', 'mobile/android/gradle/build.gradle')
srcdir('settings.gradle', 'mobile/android/gradle/settings.gradle')
@ -103,17 +100,6 @@ class MachCommands(MachCommandBase):
defines=defines,
deps=os.path.join(self.topobjdir, 'mobile/android/gradle/.deps/local.properties.pp'))
srcdir('branding/build.gradle', 'mobile/android/gradle/branding/build.gradle')
srcdir('branding/src/main/AndroidManifest.xml', 'mobile/android/gradle/branding/AndroidManifest.xml')
srcdir('branding/src/main/res', os.path.join(self.substs['MOZ_BRANDING_DIRECTORY'], 'res'))
srcdir('preprocessed_code/build.gradle', 'mobile/android/gradle/preprocessed_code/build.gradle')
srcdir('preprocessed_code/src/main/AndroidManifest.xml', 'mobile/android/gradle/preprocessed_code/AndroidManifest.xml')
srcdir('preprocessed_code/src/adjust/java/org/mozilla/gecko/adjust', 'mobile/android/base/adjust')
srcdir('preprocessed_resources/build.gradle', 'mobile/android/gradle/preprocessed_resources/build.gradle')
srcdir('preprocessed_resources/src/main/AndroidManifest.xml', 'mobile/android/gradle/preprocessed_resources/AndroidManifest.xml')
srcdir('thirdparty/build.gradle', 'mobile/android/gradle/thirdparty/build.gradle')
srcdir('thirdparty/src/main/AndroidManifest.xml', 'mobile/android/gradle/thirdparty/AndroidManifest.xml')
srcdir('thirdparty/src/main/java', 'mobile/android/thirdparty')
@ -129,8 +115,6 @@ class MachCommands(MachCommandBase):
srcdir('omnijar/src/main/java/themes', 'mobile/android/themes')
srcdir('app/build.gradle', 'mobile/android/gradle/app/build.gradle')
objdir('app/src/main/AndroidManifest.xml', 'mobile/android/base/AndroidManifest.xml')
objdir('app/src/androidTest/AndroidManifest.xml', 'build/mobile/robocop/AndroidManifest.xml')
srcdir('app/src/androidTest/res', 'build/mobile/robocop/res')
srcdir('app/src/androidTest/assets', 'mobile/android/tests/browser/robocop/assets')
# Test code.
@ -155,6 +139,7 @@ class MachCommands(MachCommandBase):
srcdir('base/src/main/res', 'mobile/android/base/resources')
srcdir('base/src/main/assets', 'mobile/android/app/assets')
srcdir('base/src/crashreporter/res', 'mobile/android/base/crashreporter/res')
srcdir('base/src/branding/res', os.path.join(self.substs['MOZ_BRANDING_DIRECTORY'], 'res'))
# JUnit 4 test code.
srcdir('base/src/background_junit4', 'mobile/android/tests/background/junit4/src')
srcdir('base/resources/background_junit4', 'mobile/android/tests/background/junit4/resources')

View File

@ -27,6 +27,7 @@ support-files =
[test_reader_view.html]
[test_resource_substitutions.html]
[test_restricted_profiles.html]
[test_selectoraddtab.html]
[test_session_form_data.html]
[test_shared_preferences.html]
[test_simple_discovery.html]

View File

@ -0,0 +1,105 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1216047
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1216047</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="head.js"></script>
<script type="application/javascript;version=1.7">
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Messaging.jsm");
Cu.import("resource://gre/modules/Task.jsm");
function promiseTabEvent(container, eventType) {
return new Promise((resolve) => {
function handle(event) {
info("Received event " + eventType + " from container");
container.removeEventListener(eventType, handle, true);
resolve(event);
}
container.addEventListener(eventType, handle, true);
info("Now waiting for " + eventType + " event from container");
});
}
// The chrome window
let chromeWin;
// Track the <browser>s where the tests are happening
let browserBlank;
let browserTest;
const kTestPage = "http://mochi.test:8888/chrome/mobile/android/tests/browser/chrome/basic_article.html";
add_task(function* test_selectOrAdd() {
chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
let BrowserApp = chromeWin.BrowserApp;
SimpleTest.registerCleanupFunction(function() {
BrowserApp.closeTab(BrowserApp.getTabForBrowser(browserBlank));
BrowserApp.closeTab(BrowserApp.getTabForBrowser(browserTest));
});
// Add a new tab with a blank page
browserBlank = BrowserApp.addTab("about:blank", { selected: true, parentId: BrowserApp.selectedTab.id }).browser;
// Now, let's force the target browser to be added
browserTest = BrowserApp.selectOrAddTab(kTestPage, { selected: true, parentId: BrowserApp.selectedTab.id }).browser;
yield promiseBrowserEvent(browserTest, "DOMContentLoaded");
// Check that basic_article is now selected
is(BrowserApp.selectedBrowser, browserTest, "Target browser is selected after being added.");
// Switch back to about:blank
BrowserApp.selectTab(BrowserApp.getTabForBrowser(browserBlank));
yield promiseTabEvent(BrowserApp.deck, "TabSelect");
// Check that about:blank is selected
is(BrowserApp.selectedBrowser, browserBlank, "about:blank is selected.");
// Use selectOrAddTab to select the existing tab
BrowserApp.selectOrAddTab(kTestPage, { selected: true, parentId: BrowserApp.selectedTab.id }).browser;
yield promiseTabEvent(BrowserApp.deck, "TabSelect");
// Check that basic_article is now selected
is(BrowserApp.selectedBrowser, browserTest, "Target browser is selected.");
// Switch back to about:blank
BrowserApp.selectTab(BrowserApp.getTabForBrowser(browserBlank));
yield promiseTabEvent(BrowserApp.deck, "TabSelect");
// Check that about:blank is selected
is(BrowserApp.selectedBrowser, browserBlank, "about:blank is selected.");
// Use selectOrAddTab to select the existing tab using the startsWith flag
BrowserApp.selectOrAddTab(kTestPage, { selected: true, parentId: BrowserApp.selectedTab.id }, { startsWith: kTestPage }).browser;
yield promiseTabEvent(BrowserApp.deck, "TabSelect");
// Check that basic_article is now selected
is(BrowserApp.selectedBrowser, browserTest, "Target browser is selected.");
});
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1216047">Mozilla Bug 1216047</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -10,8 +10,6 @@
#include "nsIURI.h"
#include "nsXPIDLString.h"
#define ALERTS_BUNDLE "chrome://alerts/locale/alert.properties"
/* static */
bool
nsAlertsUtils::IsActionablePrincipal(nsIPrincipal* aPrincipal)
@ -21,35 +19,6 @@ nsAlertsUtils::IsActionablePrincipal(nsIPrincipal* aPrincipal)
!aPrincipal->GetIsNullPrincipal();
}
/* static */
void
nsAlertsUtils::GetSource(nsIPrincipal* aPrincipal, nsAString& aSource)
{
nsAutoString hostPort;
GetSourceHostPort(aPrincipal, hostPort);
if (hostPort.IsEmpty()) {
return;
}
nsCOMPtr<nsIStringBundleService> stringService(
mozilla::services::GetStringBundleService());
if (!stringService) {
return;
}
nsCOMPtr<nsIStringBundle> alertsBundle;
if (NS_WARN_IF(NS_FAILED(stringService->CreateBundle(ALERTS_BUNDLE,
getter_AddRefs(alertsBundle))))) {
return;
}
const char16_t* params[1] = { hostPort.get() };
nsXPIDLString result;
if (NS_WARN_IF(NS_FAILED(
alertsBundle->FormatStringFromName(MOZ_UTF16("source.label"), params, 1,
getter_Copies(result))))) {
return;
}
aSource = result;
}
/* static */
void
nsAlertsUtils::GetSourceHostPort(nsIPrincipal* aPrincipal,

View File

@ -22,13 +22,6 @@ public:
static bool
IsActionablePrincipal(nsIPrincipal* aPrincipal);
/**
* Sets |aSource| to the localized notification source string, or an empty
* string if |aPrincipal| is not actionable.
*/
static void
GetSource(nsIPrincipal* aPrincipal, nsAString& aSource);
/**
* Sets |aHostPort| to the host and port from |aPrincipal|'s URI, or an
* empty string if |aPrincipal| is not actionable.

View File

@ -145,7 +145,7 @@ nsXULAlerts::ShowAlertNotification(const nsAString& aImageUrl, const nsAString&
nsCOMPtr<nsISupportsString> scriptableAlertSource (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
NS_ENSURE_TRUE(scriptableAlertSource, NS_ERROR_FAILURE);
nsAutoString source;
nsAlertsUtils::GetSource(aPrincipal, source);
nsAlertsUtils::GetSourceHostPort(aPrincipal, source);
scriptableAlertSource->SetData(source);
rv = argsArray->AppendElement(scriptableAlertSource);
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -32,14 +32,28 @@ function prefillAlertInfo() {
// arguments[7] --> lang
// arguments[8] --> replaced alert window (nsIDOMWindow)
// arguments[9] --> an optional callback listener (nsIObserver)
// arguments[10] -> the localized alert source string
// arguments[10] -> the nsIURI.hostPort of the origin, optional
switch (window.arguments.length) {
default:
case 11: {
if (window.arguments[10]) {
document.getElementById('alertBox').setAttribute('hasOrigin', true);
document.getElementById('alertSourceLabel').setAttribute('value', window.arguments[10]);
let alertBox = document.getElementById("alertBox");
alertBox.setAttribute("hasOrigin", true);
let hostPort = window.arguments[10];
const ALERT_BUNDLE = Services.strings.createBundle(
"chrome://alerts/locale/alert.properties");
let label = document.getElementById("alertSourceLabel");
label.setAttribute("value",
ALERT_BUNDLE.formatStringFromName("source.label",
[hostPort],
1));
let disableForOrigin = document.getElementById("disableForOriginMenuItem");
disableForOrigin.setAttribute("label",
ALERT_BUNDLE.formatStringFromName("webActions.disableForOrigin.label",
[hostPort],
1));
}
}
case 10:
@ -217,6 +231,11 @@ function onAlertClick() {
}
}
function disableForOrigin() {
gAlertListener.observe(null, "alertdisablecallback", gAlertCookie);
onAlertClose();
}
function onAlertClose() {
let alertBox = document.getElementById("alertBox");
if (alertBox.getAttribute("animate") == "true") {

View File

@ -43,7 +43,13 @@
<spacer flex="1"/>
<box id="alertFooter">
<label id="alertSourceLabel" class="alertSource plain"/>
<button type="menu" id="alertSettings" tooltiptext="&settings.label;"/>
<button type="menu" id="alertSettings" tooltiptext="&settings.label;"
onclick="event.stopPropagation();">
<menupopup position="after_end">
<menuitem id="disableForOriginMenuItem"
oncommand="disableForOrigin();"/>
</menupopup>
</button>
</box>
</vbox>
</box>

View File

@ -8,7 +8,9 @@
closeButton.title = Close
# LOCALIZATION NOTE(actionButton.label): Used as the button label to provide more actions on OS X notifications. OS X will truncate this if it's too long.
actionButton.label =
webActions.disable.label = Disable notifications from this site
# LOCALIZATION NOTE(webActions.disableForOrigin.label): %S is replaced
# with the hostname origin of the notification.
webActions.disableForOrigin.label = Disable notifications from %S
# LOCALIZATION NOTE(source.label): Used to show the URL of the site that
# sent the notification (e.g., "via mozilla.org"). "%1$S" is the source host

View File

@ -65,7 +65,6 @@ label {
border-width: 0;
min-width: 0;
list-style-image: url("chrome://mozapps/skin/extensions/utilities.svg#utilities");
visibility: hidden; /* Temporary until bug 1209602 or bug 1205172 is fixed. */
}
#alertSettings:hover {
@ -73,7 +72,7 @@ label {
border-radius: 20px;
}
#alertSettings["open"],
#alertSettings[open],
#alertSettings:hover:active {
background-color: rgba(107,107,107,.4);
}

View File

@ -245,8 +245,18 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const
nsAutoString hostPort;
nsAlertsUtils::GetSourceHostPort(aPrincipal, hostPort);
nsCOMPtr<nsIStringBundle> bundle;
nsCOMPtr<nsIStringBundleService> sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
nsresult rv = sbs->CreateBundle("chrome://alerts/locale/alert.properties", getter_AddRefs(bundle));
if (!hostPort.IsEmpty()) {
notification.subtitle = nsCocoaUtils::ToNSString(hostPort);
const char16_t* formatStrings[] = { hostPort.get() };
nsXPIDLString notificationSource;
bundle->FormatStringFromName(NS_LITERAL_STRING("source.label").get(),
formatStrings,
ArrayLength(formatStrings),
getter_Copies(notificationSource));
notification.subtitle = nsCocoaUtils::ToNSString(notificationSource);
}
notification.informativeText = nsCocoaUtils::ToNSString(aAlertText);
@ -255,17 +265,19 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const
// If this is not an application/extension alert, show additional actions dealing with permissions.
if (nsAlertsUtils::IsActionablePrincipal(aPrincipal)) {
nsCOMPtr<nsIStringBundleService> sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
nsCOMPtr<nsIStringBundle> bundle;
nsresult rv = sbs->CreateBundle("chrome://alerts/locale/alert.properties", getter_AddRefs(bundle));
if (NS_SUCCEEDED(rv)) {
nsXPIDLString closeButtonTitle, actionButtonTitle, disableButtonTitle, settingsButtonTitle;
bundle->GetStringFromName(NS_LITERAL_STRING("closeButton.title").get(),
getter_Copies(closeButtonTitle));
bundle->GetStringFromName(NS_LITERAL_STRING("actionButton.label").get(),
getter_Copies(actionButtonTitle));
bundle->GetStringFromName(NS_LITERAL_STRING("webActions.disable.label").get(),
getter_Copies(disableButtonTitle));
if (!hostPort.IsEmpty()) {
const char16_t* formatStrings[] = { hostPort.get() };
bundle->FormatStringFromName(NS_LITERAL_STRING("webActions.disableForOrigin.label").get(),
formatStrings,
ArrayLength(formatStrings),
getter_Copies(disableButtonTitle));
}
bundle->GetStringFromName(NS_LITERAL_STRING("webActions.settings.label").get(),
getter_Copies(settingsButtonTitle));