Merge mozilla-central and fx-team

This commit is contained in:
Ed Morley 2014-06-12 16:03:26 +01:00
commit 0a571c0fd9
24 changed files with 515 additions and 58 deletions

View File

@ -3,7 +3,7 @@
- You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
@ -42,7 +42,9 @@ function init_all() {
this.removeAttribute("keyboard-navigation");
});
gotoPref("paneGeneral");
if (document.getElementById("category-general").selected) {
gotoPref("paneGeneral");
}
}
function selectCategory(name) {

View File

@ -6,6 +6,7 @@ support-files =
[browser_advanced_update.js]
[browser_bug410900.js]
[browser_bug731866.js]
[browser_bug1020245_openPreferences_to_paneContent.js]
[browser_bug795764_cachedisabled.js]
[browser_connection.js]
[browser_connection_bug388287.js]

View File

@ -0,0 +1,25 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
add_task(function test() {
waitForExplicitFinish();
let deferred = Promise.defer();
gBrowser.selectedTab = gBrowser.addTab("about:blank");
openPreferences("paneContent");
let newTabBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
newTabBrowser.addEventListener("Initialized", function PrefInit() {
newTabBrowser.removeEventListener("Initialized", PrefInit, true);
newTabBrowser.contentWindow.addEventListener("load", function prefLoad() {
newTabBrowser.contentWindow.removeEventListener("load", prefLoad);
let sel = gBrowser.contentWindow.history.state;
is(sel, "paneContent", "Content pane was selected");
deferred.resolve();
gBrowser.removeCurrentTab();
});
}, true);
yield deferred.promise;
finish();
});

View File

@ -37,7 +37,7 @@ function testParseCssProperty() {
target.appendChild(frag);
is(target.innerHTML,
'1px solid <span style="background-color:red" class="test-colorswatch"></span><span>#F00</span>',
'1px solid <span data-color="#F00"><span style="background-color:red" class="test-colorswatch"></span><span>#F00</span></span>',
"CSS property correctly parsed");
target.innerHTML = "";
@ -48,8 +48,8 @@ function testParseCssProperty() {
});
target.appendChild(frag);
is(target.innerHTML,
'linear-gradient(to right, <span style="background-color:#F60" class="test-colorswatch"></span><span class="test-color">#F60</span> 10%, ' +
'<span style="background-color:rgba(0,0,0,1)" class="test-colorswatch"></span><span class="test-color">#000</span>)',
'linear-gradient(to right, <span data-color="#F60"><span style="background-color:#F60" class="test-colorswatch"></span><span class="test-color">#F60</span></span> 10%, ' +
'<span data-color="#000"><span style="background-color:rgba(0,0,0,1)" class="test-colorswatch"></span><span class="test-color">#000</span></span>)',
"Gradient CSS property correctly parsed");
target.innerHTML = "";
@ -69,7 +69,7 @@ function testParseHTMLAttribute() {
ok(target, "captain, we have the div");
target.appendChild(frag);
let expected = 'color:<span class="theme-color">#F00</span>; font-size: 12px; ' +
let expected = 'color:<span data-color="#F00"><span class="theme-color">#F00</span></span>; font-size: 12px; ' +
'background-image: url(\'<a href="chrome://branding/content/about-logo.png" ' +
'class="theme-link" ' +
'target="_blank">chrome://branding/content/about-logo.png</a>\')';

View File

@ -1011,6 +1011,7 @@ SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.pr
_selectColor: function(color) {
if (this.activeSwatch) {
this.activeSwatch.style.backgroundColor = color;
this.activeSwatch.parentNode.dataset.color = color;
this.currentSwatchColor.textContent = color;
this.preview(color);
}

View File

@ -149,6 +149,7 @@ function CssHtmlTree(aStyleInspector, aPageStyle)
this._onSelectAll = this._onSelectAll.bind(this);
this._onClick = this._onClick.bind(this);
this._onCopy = this._onCopy.bind(this);
this._onCopyColor = this._onCopyColor.bind(this);
this.styleDocument.addEventListener("copy", this._onCopy);
this.styleDocument.addEventListener("mousedown", this.focusWindow);
@ -584,6 +585,13 @@ CssHtmlTree.prototype = {
command: this._onCopy
});
// Copy color
this.menuitemCopyColor = createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.copyColor",
accesskey: "ruleView.contextmenu.copyColor.accessKey",
command: this._onCopyColor
});
// Show Original Sources
this.menuitemSources= createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.showOrigSources",
@ -619,6 +627,39 @@ CssHtmlTree.prototype = {
let accessKey = label + ".accessKey";
this.menuitemSources.setAttribute("accesskey",
CssHtmlTree.l10n(accessKey));
this.menuitemCopyColor.hidden = !this._isColorPopup();
},
/**
* A helper that determines if the popup was opened with a click to a color
* value and saves the color to this._colorToCopy.
*
* @return {Boolean}
* true if click on color opened the popup, false otherwise.
*/
_isColorPopup: function () {
this._colorToCopy = "";
let trigger = this.popupNode;
if (!trigger) {
return false;
}
let container = (trigger.nodeType == trigger.TEXT_NODE) ?
trigger.parentElement : trigger;
let isColorNode = el => el.dataset && "color" in el.dataset;
while (!isColorNode(container)) {
container = container.parentNode;
if (!container) {
return false;
}
}
this._colorToCopy = container.dataset["color"];
return true;
},
/**
@ -626,6 +667,7 @@ CssHtmlTree.prototype = {
*/
_onContextMenu: function(event) {
try {
this.popupNode = event.explicitOriginalTarget;
this.styleDocument.defaultView.focus();
this._contextmenu.openPopupAtScreen(event.screenX, event.screenY, true);
} catch(e) {
@ -660,6 +702,10 @@ CssHtmlTree.prototype = {
}
},
_onCopyColor: function() {
clipboardHelper.copyString(this._colorToCopy, this.styleDocument);
},
/**
* Copy selected text.
*
@ -751,12 +797,18 @@ CssHtmlTree.prototype = {
this.menuitemSelectAll.removeEventListener("command", this._onSelectAll);
this.menuitemSelectAll = null;
// Destroy Copy Color menuitem.
this.menuitemCopyColor.removeEventListener("command", this._onCopyColor);
this.menuitemCopyColor = null;
// Destroy the context menu.
this._contextmenu.removeEventListener("popupshowing", this._contextMenuUpdate);
this._contextmenu.parentNode.removeChild(this._contextmenu);
this._contextmenu = null;
}
this.popupNode = null;
this.tooltip.stopTogglingOnHover(this.propertyContainer);
this.tooltip.destroy();

View File

@ -1079,6 +1079,7 @@ function CssRuleView(aInspector, aDoc, aStore, aPageStyle) {
this._contextMenuUpdate = this._contextMenuUpdate.bind(this);
this._onSelectAll = this._onSelectAll.bind(this);
this._onCopy = this._onCopy.bind(this);
this._onCopyColor = this._onCopyColor.bind(this);
this._onToggleOrigSources = this._onToggleOrigSources.bind(this);
this.element.addEventListener("copy", this._onCopy);
@ -1138,6 +1139,11 @@ CssRuleView.prototype = {
accesskey: "ruleView.contextmenu.copy.accessKey",
command: this._onCopy
});
this.menuitemCopyColor = createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.copyColor",
accesskey: "ruleView.contextmenu.copyColor.accessKey",
command: this._onCopyColor
});
this.menuitemSources= createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.showOrigSources",
accesskey: "ruleView.contextmenu.showOrigSources.accessKey",
@ -1261,6 +1267,7 @@ CssRuleView.prototype = {
copy = false;
}
this.menuitemCopyColor.hidden = !this._isColorPopup();
this.menuitemCopy.disabled = !copy;
let label = "ruleView.contextmenu.showOrigSources";
@ -1275,6 +1282,37 @@ CssRuleView.prototype = {
_strings.GetStringFromName(accessKey));
},
/**
* A helper that determines if the popup was opened with a click to a color
* value and saves the color to this._colorToCopy.
*
* @return {Boolean}
* true if click on color opened the popup, false otherwise.
*/
_isColorPopup: function () {
this._colorToCopy = "";
let trigger = this.doc.popupNode;
if (!trigger) {
return false;
}
let container = (trigger.nodeType == trigger.TEXT_NODE) ?
trigger.parentElement : trigger;
let isColorNode = el => el.dataset && "color" in el.dataset;
while (!isColorNode(container)) {
container = container.parentNode;
if (!container) {
return false;
}
}
this._colorToCopy = container.dataset["color"];
return true;
},
/**
* Select all text.
*/
@ -1327,6 +1365,13 @@ CssRuleView.prototype = {
}
},
/**
* Copy the most recently selected color value to clipboard.
*/
_onCopyColor: function() {
clipboardHelper.copyString(this._colorToCopy, this.styleDocument);
},
/**
* Toggle the original sources pref.
*/
@ -1400,6 +1445,10 @@ CssRuleView.prototype = {
this.menuitemCopy.removeEventListener("command", this._onCopy);
this.menuitemCopy = null;
// Destroy Copy Color menuitem.
this.menuitemCopyColor.removeEventListener("command", this._onCopyColor);
this.menuitemCopyColor = null;
this.menuitemSources.removeEventListener("command", this._onToggleOrigSources);
this.menuitemSources = null;

View File

@ -87,6 +87,8 @@ skip-if = os == "win" && debug # bug 963492
[browser_ruleview_user-agent-styles.js]
[browser_ruleview_user-agent-styles-uneditable.js]
[browser_ruleview_user-property-reset.js]
[browser_styleinspector_context-menu-copy-color_01.js]
[browser_styleinspector_context-menu-copy-color_02.js]
[browser_styleinspector_csslogic-content-stylesheets.js]
[browser_styleinspector_csslogic-inherited-properties.js]
[browser_styleinspector_csslogic-specificity.js]

View File

@ -0,0 +1,139 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test "Copy color" item of the context menu #1: Test _isColorPopup.
const TEST_COLOR = "#123ABC";
const COLOR_SELECTOR = "span[data-color]";
let test = asyncTest(function* () {
const TEST_DOC = '<html> \
<body> \
<div style="color: ' + TEST_COLOR + '; \
margin: 0px; \
background: ' + TEST_COLOR + ';"> \
Test "Copy color" context menu option \
</div> \
</body> \
</html>';
const TEST_CASES = [
{
viewName: "RuleView",
initializer: openRuleView
},
{
viewName: "ComputedView",
initializer: openComputedView
}
];
yield addTab("data:text/html;charset=utf8," + encodeURIComponent(TEST_DOC));
for (let test of TEST_CASES) {
yield testView(test);
}
});
function* testView({viewName, initializer}) {
info("Testing " + viewName);
let {inspector, view} = yield initializer();
yield selectNode("div", inspector);
testIsColorValueNode(view);
testIsColorPopupOnAllNodes(view);
yield clearCurrentNodeSelection(inspector);
}
/**
* A function testing that isColorValueNode correctly detects nodes part of
* color values.
*/
function testIsColorValueNode(view) {
info("Testing that child nodes of color nodes are detected.");
let root = rootElement(view);
let colorNode = root.querySelector(COLOR_SELECTOR);
ok(colorNode, "Color node found");
for (let node of iterateNodes(colorNode)) {
ok(isColorValueNode(node), "Node is part of color value.");
}
}
/**
* A function testing that _isColorPopup returns a correct value for all nodes
* in the view.
*/
function testIsColorPopupOnAllNodes(view) {
let root = rootElement(view);
for (let node of iterateNodes(root)) {
testIsColorPopupOnNode(view, node);
}
}
/**
* Test result of _isColorPopup with given node.
* @param object view
* A CSSRuleView or CssHtmlTree instance.
* @param Node node
* A node to check.
*/
function testIsColorPopupOnNode(view, node) {
info("Testing node " + node);
if (view.doc) {
view.doc.popupNode = node;
}
else {
view.popupNode = node;
}
view._colorToCopy = "";
let result = view._isColorPopup();
let correct = isColorValueNode(node);
is(result, correct, "_isColorPopup returned the expected value " + correct);
is(view._colorToCopy, (correct) ? TEST_COLOR : "",
"_colorToCopy was set to the expected value");
}
/**
* Check if a node is part of color value i.e. it has parent with a 'data-color'
* attribute.
*/
function isColorValueNode(node) {
let container = (node.nodeType == node.TEXT_NODE) ?
node.parentElement : node;
let isColorNode = el => el.dataset && "color" in el.dataset;
while (!isColorNode(container)) {
container = container.parentNode;
if (!container) {
info("No color. Node is not part of color value.");
return false;
}
}
info("Found a color. Node is part of color value.");
return true;
}
/**
* A generator that iterates recursively trough all child nodes of baseNode.
*/
function* iterateNodes(baseNode) {
yield baseNode;
for (let child of baseNode.childNodes) {
yield* iterateNodes(child);
}
}
/**
* Returns the root element for the given view, rule or computed.
*/
let rootElement = view => (view.element) ? view.element : view.styleDocument;

View File

@ -0,0 +1,99 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test "Copy color" item of the context menu #2: Test that correct color is
// copied if the color changes.
const TEST_COLOR = "#123ABC";
let test = asyncTest(function* () {
const PAGE_CONTENT = [
'<style type="text/css">',
' div {',
' color: ' + TEST_COLOR + ';',
' }',
'</style>',
'<div>Testing the color picker tooltip!</div>'
].join("\n");
yield addTab("data:text/html;charset=utf8,Test context menu Copy color");
content.document.body.innerHTML = PAGE_CONTENT;
let {inspector, view} = yield openRuleView();
yield testCopyToClipboard(inspector, view);
yield testManualEdit(inspector, view);
yield testColorPickerEdit(inspector, view);
});
function* testCopyToClipboard(inspector, view) {
info("Testing that color is copied to clipboard");
yield selectNode("div", inspector);
let win = view.doc.defaultView;
let element = getRuleViewProperty(view, "div", "color").valueSpan
.querySelector(".ruleview-colorswatch");
let popup = once(view._contextmenu, "popupshown");
EventUtils.synthesizeMouseAtCenter(element, {button: 2, type: "contextmenu"}, win);
yield popup;
ok(!view.menuitemCopyColor.hidden, "Copy color is visible");
yield waitForClipboard(() => view.menuitemCopyColor.click(), TEST_COLOR);
view._contextmenu.hidePopup();
}
function* testManualEdit(inspector, view) {
info("Testing manually edited colors");
yield selectNode("div", inspector);
let {valueSpan} = getRuleViewProperty(view, "div", "color");
let newColor = "#C9184E"
let editor = yield focusEditableField(valueSpan);
info("Typing new value");
let input = editor.input;
let onBlur = once(input, "blur");
for (let ch of newColor + ";"){
EventUtils.sendChar(ch, view.doc.defaultView);
}
yield onBlur;
yield wait(1);
let colorValue = getRuleViewProperty(view, "div", "color").valueSpan.firstChild;
is(colorValue.dataset.color, newColor, "data-color was updated");
view.doc.popupNode = colorValue;
view._isColorPopup();
is(view._colorToCopy, newColor, "_colorToCopy has the new value");
}
function* testColorPickerEdit(inspector, view) {
info("Testing colors edited via color picker");
yield selectNode("div", inspector);
let swatch = getRuleViewProperty(view, "div", "color").valueSpan
.querySelector(".ruleview-colorswatch");
info("Opening the color picker");
let picker = view.colorPicker;
let onShown = picker.tooltip.once("shown");
swatch.click();
yield onShown;
let rgbaColor = [83, 183, 89, 1];
let rgbaColorText = "rgba(83, 183, 89, 1)";
yield simulateColorPickerChange(picker, rgbaColor);
is(swatch.parentNode.dataset.color, rgbaColorText, "data-color was updated");
view.doc.popupNode = swatch;
view._isColorPopup();
is(view._colorToCopy, rgbaColorText, "_colorToCopy has the new value");
}

View File

@ -73,7 +73,7 @@ function test() {
name: "background-color",
value: "transparent",
test: fragment => {
is(countAll(fragment), 1);
is(countAll(fragment), 2);
is(countColors(fragment), 1);
is(fragment.textContent, "transparent");
}
@ -98,7 +98,7 @@ function test() {
name: "border",
value: "80em dotted pink",
test: fragment => {
is(countAll(fragment), 1);
is(countAll(fragment), 2);
is(countColors(fragment), 1);
is(getColor(fragment), "pink");
}
@ -119,7 +119,7 @@ function test() {
is(countUrls(fragment), 1);
is(getColor(fragment), "red");
is(getUrl(fragment), "test.png");
is(countAll(fragment), 2);
is(countAll(fragment), 3);
}
},
{
@ -130,7 +130,7 @@ function test() {
is(countUrls(fragment), 1);
is(getColor(fragment), "blue");
is(getUrl(fragment), "test.png");
is(countAll(fragment), 2);
is(countAll(fragment), 3);
}
},
{
@ -163,7 +163,7 @@ function test() {
name: "background",
value: "linear-gradient(to right, rgba(183,222,237,1) 0%, rgba(33,180,226,1) 30%, rgba(31,170,217,.5) 44%, #F06 75%, red 100%)",
test: fragment => {
is(countAll(fragment), 5);
is(countAll(fragment), 10);
let allSwatches = fragment.querySelectorAll("." + COLOR_CLASS);
is(allSwatches.length, 5);
is(allSwatches[0].textContent, "rgba(183,222,237,1)");
@ -177,7 +177,7 @@ function test() {
name: "background",
value: "-moz-radial-gradient(center 45deg, circle closest-side, orange 0%, red 100%)",
test: fragment => {
is(countAll(fragment), 2);
is(countAll(fragment), 4);
let allSwatches = fragment.querySelectorAll("." + COLOR_CLASS);
is(allSwatches.length, 2);
is(allSwatches[0].textContent, "orange");
@ -188,7 +188,7 @@ function test() {
name: "background",
value: "white url(http://test.com/wow_such_image.png) no-repeat top left",
test: fragment => {
is(countAll(fragment), 2);
is(countAll(fragment), 3);
is(countUrls(fragment), 1);
is(countColors(fragment), 1);
}
@ -213,7 +213,7 @@ function test() {
name: "background",
value: "red url( \"http://wow.com/cool/../../../you're(doingit)wrong\" ) repeat center",
test: fragment => {
is(countAll(fragment), 2);
is(countAll(fragment), 3);
is(countColors(fragment), 1);
is(getUrl(fragment), "http://wow.com/cool/../../../you're(doingit)wrong");
}

View File

@ -56,11 +56,13 @@
tabindex="0"/>
</toolbar>
<splitter class="devtools-horizontal-splitter"/>
<box id="web-audio-content-pane" flex="1">
<box id="web-audio-content-pane"
class="devtools-responsive-container"
flex="1">
<hbox flex="1">
<box id="web-audio-graph" class="devtools-responsive-container" flex="1">
<box id="web-audio-graph" flex="1">
<vbox flex="1">
<svg id="graph-svg" flex="1" viewBox="0 0 1000 500"
<svg id="graph-svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph-target" transform="translate(20,20)"/>

View File

@ -1396,7 +1396,7 @@ mediaResetDesc=Stop emulating a CSS media type
# injectFailed) These strings describe the 'inject' commands and all available
# parameters.
injectDesc=Inject common libraries into the page
injectManual=Inject common libraries into the content of the page which can also be accessed from the Firefox console.
injectManual2=Inject common libraries into the content of the page which can also be accessed from the console.
injectLibraryDesc=Select the library to inject or enter a valid script URI to inject
injectLoaded=%1$S loaded
injectFailed=Failed to load %1$S - Invalid URI

View File

@ -86,3 +86,11 @@ description {
font-size: 1.25rem;
line-height: 22px;
}
#popupPolicyRow {
/* Override styles from
browser/themes/osx/preferences/preferences.css */
margin-bottom: 0 !important;
padding-bottom: 0 !important;
border-bottom: none;
}

View File

@ -134,9 +134,7 @@ caption {
-moz-box-align: center;
}
#popupPolicyRow,
#enableSoftwareInstallRow,
#enableImagesRow {
#popupPolicyRow {
margin-bottom: 4px !important;
padding-bottom: 4px !important;
border-bottom: 1px solid #ccc;

View File

@ -139,7 +139,9 @@ panelmultiview[nosubviews=true] > .panel-viewcontainer > .panel-viewstack > .pan
.panel-subview-header,
.subviewbutton.panel-subview-footer {
padding: 12px;
box-sizing: border-box;
min-height: 41px;
padding: 11px 12px;
}
.panel-subview-header {
@ -490,8 +492,9 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
#PanelUI-customize,
#PanelUI-quit {
margin: 0;
padding: 10px 0;
min-height: 2em;
padding: 11px 0;
box-sizing: border-box;
min-height: 40px;
-moz-appearance: none;
box-shadow: none;
border: none;

View File

@ -40,8 +40,8 @@
/* Context Graph */
svg {
position: fixed;
overflow: hidden;
-moz-box-flex: 1;
}
/* Edges in graph */
@ -111,12 +111,6 @@ text {
transition: opacity .5s ease-out 0s;
}
@media (min-resolution: 2dppx) {
.web-audio-inspector .error {
background-image: url(alerticon-warning@2x.png);
}
}
#inspector-pane-toggle {
background: none;
box-shadow: none;
@ -151,4 +145,28 @@ text {
#inspector-pane-toggle:active {
-moz-image-region: rect(0px,64px,32px,32px);
}
}
.web-audio-inspector .error {
background-image: url(alerticon-warning@2x.png);
}
}
/**
* Responsive Styles
* `.devtools-responsive-container` takes care of most of
* the changing of host types.
*/
@media (max-width: 700px) {
/**
* Override the inspector toggle so it's always open
* in the portrait view, with the toggle button hidden.
*/
#inspector-pane-toggle {
display: none;
}
#web-audio-inspector {
margin-left: 0px !important;
margin-right: 0px !important;
}
}

View File

@ -121,10 +121,13 @@ XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu",
Services.scriptloader.loadSubScript(script, sandbox);
return sandbox[name];
});
notifications.forEach(function (aNotification) {
Services.obs.addObserver(function(s, t, d) {
window[name].observe(s, t, d)
}, aNotification, false);
let observer = (s, t, d) => {
Services.obs.removeObserver(observer, t);
Services.obs.addObserver(window[name], t, false);
window[name].observe(s, t, d); // Explicitly notify new observer
};
notifications.forEach((notification) => {
Services.obs.addObserver(observer, notification, false);
});
});
@ -135,10 +138,13 @@ XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu",
].forEach(module => {
let [name, notifications, resource] = module;
XPCOMUtils.defineLazyModuleGetter(this, name, resource);
let observer = (s, t, d) => {
Services.obs.removeObserver(observer, t);
Services.obs.addObserver(this[name], t, false);
this[name].observe(s, t, d); // Explicitly notify new observer
};
notifications.forEach(notification => {
Services.obs.addObserver((s,t,d) => {
this[name].observe(s,t,d)
}, notification, false);
Services.obs.addObserver(observer, notification, false);
});
});

View File

@ -41,7 +41,7 @@ want to do then dive in!
.. toctree::
:maxdepth: 2
manifestdestiny
manifestparser
gettinginfo
setuprunning
mozhttpd

View File

@ -33,6 +33,7 @@ class LocalAppNotFoundError(VersionError):
INI_DATA_MAPPING = (('application', 'App'), ('platform', 'Build'))
class Version(mozlog.LoggingMixin):
def __init__(self):
@ -62,6 +63,7 @@ class Version(mozlog.LoggingMixin):
self._info['application_display_name'] = \
self._info.get('application_name')
class LocalFennecVersion(Version):
def __init__(self, path, **kwargs):
@ -78,6 +80,7 @@ class LocalFennecVersion(Version):
else:
self.warn('Unable to find %s' % filename)
class LocalVersion(Version):
def __init__(self, binary, **kwargs):
@ -168,11 +171,12 @@ class LocalB2GVersion(B2GVersion):
class RemoteB2GVersion(B2GVersion):
def __init__(self, sources=None, dm_type='adb', host=None, **kwargs):
def __init__(self, sources=None, dm_type='adb', host=None,
device_serial=None, **kwargs):
B2GVersion.__init__(self, sources, **kwargs)
if dm_type == 'adb':
dm = mozdevice.DeviceManagerADB()
dm = mozdevice.DeviceManagerADB(deviceSerial=device_serial)
elif dm_type == 'sut':
if not host:
raise Exception('A host for SUT must be supplied.')
@ -218,7 +222,8 @@ class RemoteB2GVersion(B2GVersion):
self._info[desired_props[key]] = value
def get_version(binary=None, sources=None, dm_type=None, host=None):
def get_version(binary=None, sources=None, dm_type=None, host=None,
device_serial=None):
"""
Returns the application version information as a dict. You can specify
a path to the binary of the application or an Android APK file (to get
@ -231,6 +236,7 @@ def get_version(binary=None, sources=None, dm_type=None, host=None):
:param sources: Path to the sources.xml file (Firefox OS)
:param dm_type: Device manager type. Must be 'adb' or 'sut' (Firefox OS)
:param host: Host address of remote Firefox OS instance (SUT)
:param device_serial: Serial identifier of Firefox OS device (ADB)
"""
try:
if binary and zipfile.is_zipfile(binary) and 'AndroidManifest.xml' in \
@ -241,7 +247,8 @@ def get_version(binary=None, sources=None, dm_type=None, host=None):
if version._info.get('application_name') == 'B2G':
version = LocalB2GVersion(binary, sources=sources)
except LocalAppNotFoundError:
version = RemoteB2GVersion(sources=sources, dm_type=dm_type, host=host)
version = RemoteB2GVersion(sources=sources, dm_type=dm_type, host=host,
device_serial=device_serial)
return version._info
@ -253,13 +260,17 @@ def cli(args=sys.argv[1:]):
parser.add_option('--sources',
dest='sources',
help='path to sources.xml (Firefox OS only)')
parser.add_option('--device',
help='serial identifier of device to target (Firefox OS '
'only)')
(options, args) = parser.parse_args(args)
dm_type = os.environ.get('DM_TRANS', 'adb')
host = os.environ.get('TEST_DEVICE')
version = get_version(binary=options.binary, sources=options.sources,
dm_type=dm_type, host=host)
dm_type=dm_type, host=host,
device_serial=options.device)
for (key, value) in sorted(version.items()):
if value:
print '%s: %s' % (key, value)

View File

@ -12,7 +12,7 @@ exports.items = [
{
name: "inject",
description: gcli.lookup("injectDesc"),
manual: gcli.lookup("injectManual"),
manual: gcli.lookup("injectManual2"),
params: [{
name: 'library',
type: {

View File

@ -328,18 +328,29 @@ OutputParser.prototype = {
let colorObj = new colorUtils.CssColor(color);
if (this._isValidColor(colorObj)) {
let container = this._createNode("span", {
"data-color": color
});
if (options.colorSwatchClass) {
this._appendNode("span", {
let swatch = this._createNode("span", {
class: options.colorSwatchClass,
style: "background-color:" + color
});
container.appendChild(swatch);
}
if (options.defaultColorType) {
color = colorObj.toString();
container.dataset["color"] = color;
}
this._appendNode("span", {
let value = this._createNode("span", {
class: options.colorClass
}, color);
container.appendChild(value);
this.parsed.push(container);
return true;
}
return false;
@ -380,7 +391,7 @@ OutputParser.prototype = {
},
/**
* Append a node to the output.
* Create a node.
*
* @param {String} tagName
* Tag type e.g. "div"
@ -389,8 +400,9 @@ OutputParser.prototype = {
* @param {String} [value]
* If a value is included it will be appended as a text node inside
* the tag. This is useful e.g. for span tags.
* @return {Node} Newly created Node.
*/
_appendNode: function(tagName, attributes, value="") {
_createNode: function(tagName, attributes, value="") {
let win = Services.appShell.hiddenDOMWindow;
let doc = win.document;
let node = doc.createElementNS(HTML_NS, tagName);
@ -407,6 +419,22 @@ OutputParser.prototype = {
node.appendChild(textNode);
}
return node;
},
/**
* Append a node to the output.
*
* @param {String} tagName
* Tag type e.g. "div"
* @param {Object} attributes
* e.g. {class: "someClass", style: "cursor:pointer"};
* @param {String} [value]
* If a value is included it will be appended as a text node inside
* the tag. This is useful e.g. for span tags.
*/
_appendNode: function(tagName, attributes, value="") {
let node = this._createNode(tagName, attributes, value);
this.parsed.push(node);
},

View File

@ -80,6 +80,14 @@ ruleView.contextmenu.copy=Copy
# the rule view context menu "Select all" entry.
ruleView.contextmenu.copy.accessKey=C
# LOCALIZATION NOTE (ruleView.contextmenu.copyColor): Text displayed in the rule
# and computed view context menu when a color value was clicked.
ruleView.contextmenu.copyColor=Copy Color
# LOCALIZATION NOTE (ruleView.contextmenu.copyColor.accessKey): Access key for
# the rule and computed view context menu "Copy Color" entry.
ruleView.contextmenu.copyColor.accessKey=L
# LOCALIZATION NOTE (ruleView.contextmenu.showOrigSources): Text displayed in the rule view
# context menu.
ruleView.contextmenu.showOrigSources=Show original sources

View File

@ -133,7 +133,7 @@ public:
return nullptr;
}
JSContext* const cx = container->mThreadContext;
JS::RootedObject object(cx, container->mJSObject);
JS::RootedObject object(cx, *container->mJSObject);
MOZ_ASSERT(object);
JSAutoStructuredCloneBuffer buffer;
@ -179,9 +179,9 @@ public:
const jint index = env->GetIntField(object, jObjectIndex);
if (index < 0) {
// -1 for index field means it's the root object of the container
return container->mJSObject;
return *container->mJSObject;
}
return container->mRootedObjects[index];
return *container->mRootedObjects[index];
}
static jobject CreateObjectInstance(JNIEnv* env, jobject object,
@ -197,7 +197,8 @@ public:
return nullptr;
}
size_t newIndex = container->mRootedObjects.length();
if (!container->mRootedObjects.append(jsObject)) {
PersistentObjectPtr rootedJSObject(new PersistentObject(cx, jsObject));
if (!container->mRootedObjects.append(Move(rootedJSObject))) {
AndroidBridge::ThrowException(env,
"java/lang/OutOfMemoryError", "Cannot allocate object");
return nullptr;
@ -231,7 +232,7 @@ public:
MOZ_ASSERT(mBuffer.data());
MOZ_ALWAYS_TRUE(mBuffer.read(mThreadContext, &value));
if (value.isObject()) {
mJSObject = &value.toObject();
mJSObject = new PersistentObject(mThreadContext, &value.toObject());
}
if (!mJSObject) {
AndroidBridge::ThrowException(env,
@ -278,22 +279,25 @@ private:
return newObject;
}
typedef JS::PersistentRooted<JSObject*> PersistentObject;
typedef ScopedDeletePtr<PersistentObject> PersistentObjectPtr;
// Thread that the object is valid on
PRThread* mThread;
// Context that the object is valid in
JSContext* mThreadContext;
// Deserialized object, or nullptr if object is in serialized form
JS::Heap<JSObject*> mJSObject;
PersistentObjectPtr mJSObject;
// Serialized object, or empty if object is in deserialized form
JSAutoStructuredCloneBuffer mBuffer;
// Objects derived from mJSObject
Vector<JS::Heap<JSObject*>, 4> mRootedObjects;
Vector<PersistentObjectPtr, 0> mRootedObjects;
// Create a new container containing the given deserialized object
NativeJSContainer(JSContext* cx, JS::HandleObject object)
: mThread(PR_GetCurrentThread())
, mThreadContext(cx)
, mJSObject(object)
, mJSObject(new PersistentObject(cx, object))
{
}
@ -301,6 +305,7 @@ private:
NativeJSContainer(JSContext* cx, JSAutoStructuredCloneBuffer&& buffer)
: mThread(PR_GetCurrentThread())
, mThreadContext(cx)
, mJSObject(nullptr)
, mBuffer(Forward<JSAutoStructuredCloneBuffer>(buffer))
{
}