Bug 1024693 - [rule view] Copy CSS declarations r=pbrosset

This commit is contained in:
Gabriel Luong ext:(%2C%20Vikneshwar%20%3Clviknesh%40gmail.com%3E) 2015-06-10 15:08:27 -07:00
parent 3276349f43
commit 9227dd3edd
8 changed files with 578 additions and 48 deletions

View File

@ -958,6 +958,21 @@ Rule.prototype = {
} else { } else {
aTextProperty.rule.editor.closeBrace.focus(); aTextProperty.rule.editor.closeBrace.focus();
} }
},
/**
* Return a string representation of the rule.
*/
stringifyRule: function() {
let selectorText = this.selectorText;
let cssText = "";
let terminator = osString == "WINNT" ? "\r\n" : "\n";
for (let textProp of this.textProps) {
cssText += "\t" + textProp.stringifyProperty() + terminator;
}
return selectorText + " {" + terminator + cssText + "}";
} }
}; };
@ -1083,6 +1098,21 @@ TextProperty.prototype = {
remove: function() { remove: function() {
this.rule.removeProperty(this); this.rule.removeProperty(this);
},
/**
* Return a string representation of the rule property.
*/
stringifyProperty: function() {
// Get the displayed property value
let declaration = this.name + ": " + this.editor.committed.value + ";";
// Comment out property declarations that are not enabled
if (!this.enabled) {
declaration = "/* " + declaration + " */";
}
return declaration;
} }
}; };
@ -1136,6 +1166,12 @@ function CssRuleView(aInspector, aDoc, aStore, aPageStyle) {
this._onCopy = this._onCopy.bind(this); this._onCopy = this._onCopy.bind(this);
this._onCopyColor = this._onCopyColor.bind(this); this._onCopyColor = this._onCopyColor.bind(this);
this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this); this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this);
this._onCopyLocation = this._onCopyLocation.bind(this);
this._onCopyPropertyDeclaration = this._onCopyPropertyDeclaration.bind(this);
this._onCopyPropertyName = this._onCopyPropertyName.bind(this);
this._onCopyPropertyValue = this._onCopyPropertyValue.bind(this);
this._onCopyRule = this._onCopyRule.bind(this);
this._onCopySelector = this._onCopySelector.bind(this);
this._onToggleOrigSources = this._onToggleOrigSources.bind(this); this._onToggleOrigSources = this._onToggleOrigSources.bind(this);
this._onShowMdnDocs = this._onShowMdnDocs.bind(this); this._onShowMdnDocs = this._onShowMdnDocs.bind(this);
this._onFilterStyles = this._onFilterStyles.bind(this); this._onFilterStyles = this._onFilterStyles.bind(this);
@ -1223,31 +1259,70 @@ CssRuleView.prototype = {
this._contextmenu.addEventListener("popupshowing", this._contextMenuUpdate); this._contextmenu.addEventListener("popupshowing", this._contextMenuUpdate);
this._contextmenu.id = "rule-view-context-menu"; this._contextmenu.id = "rule-view-context-menu";
this.menuitemAddRule = createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.addNewRule",
accesskey: "ruleView.contextmenu.addNewRule.accessKey",
command: this._onAddRule
});
this.menuitemSelectAll = createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.selectAll",
accesskey: "ruleView.contextmenu.selectAll.accessKey",
command: this._onSelectAll
});
this.menuitemCopy = createMenuItem(this._contextmenu, { this.menuitemCopy = createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.copy", label: "ruleView.contextmenu.copy",
accesskey: "ruleView.contextmenu.copy.accessKey", accesskey: "ruleView.contextmenu.copy.accessKey",
command: this._onCopy command: this._onCopy
}); });
this.menuitemCopyLocation = createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.copyLocation",
command: this._onCopyLocation
});
this.menuitemCopyRule = createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.copyRule",
command: this._onCopyRule
});
this.menuitemCopyColor = createMenuItem(this._contextmenu, { this.menuitemCopyColor = createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.copyColor", label: "ruleView.contextmenu.copyColor",
accesskey: "ruleView.contextmenu.copyColor.accessKey", accesskey: "ruleView.contextmenu.copyColor.accessKey",
command: this._onCopyColor command: this._onCopyColor
}); });
this.menuitemCopyImageDataUrl = createMenuItem(this._contextmenu, { this.menuitemCopyImageDataUrl = createMenuItem(this._contextmenu, {
label: "styleinspector.contextmenu.copyImageDataUrl", label: "styleinspector.contextmenu.copyImageDataUrl",
accesskey: "styleinspector.contextmenu.copyImageDataUrl.accessKey", accesskey: "styleinspector.contextmenu.copyImageDataUrl.accessKey",
command: this._onCopyImageDataUrl command: this._onCopyImageDataUrl
}); });
this.menuitemCopyPropertyDeclaration = createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.copyPropertyDeclaration",
command: this._onCopyPropertyDeclaration
});
this.menuitemCopyPropertyName = createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.copyPropertyName",
command: this._onCopyPropertyName
});
this.menuitemCopyPropertyValue = createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.copyPropertyValue",
command: this._onCopyPropertyValue
});
this.menuitemCopySelector = createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.copySelector",
command: this._onCopySelector
});
createMenuSeparator(this._contextmenu);
this.menuitemSelectAll = createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.selectAll",
accesskey: "ruleView.contextmenu.selectAll.accessKey",
command: this._onSelectAll
});
createMenuSeparator(this._contextmenu);
this.menuitemAddRule = createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.addNewRule",
accesskey: "ruleView.contextmenu.addNewRule.accessKey",
command: this._onAddRule
});
this.menuitemSources = createMenuItem(this._contextmenu, { this.menuitemSources = createMenuItem(this._contextmenu, {
label: "ruleView.contextmenu.showOrigSources", label: "ruleView.contextmenu.showOrigSources",
accesskey: "ruleView.contextmenu.showOrigSources.accessKey", accesskey: "ruleView.contextmenu.showOrigSources.accessKey",
@ -1360,6 +1435,23 @@ CssRuleView.prototype = {
* appropriate. * appropriate.
*/ */
_contextMenuUpdate: function() { _contextMenuUpdate: function() {
this._enableCopyMenuItems(this.doc.popupNode.parentNode);
this.menuitemAddRule.disabled = this.inspector.selection.isAnonymousNode();
this.menuitemShowMdnDocs.hidden = !this.enableMdnDocsTooltip ||
!this.doc.popupNode.parentNode
.classList.contains(PROPERTY_NAME_CLASS);
let showOrig = Services.prefs.getBoolPref(PREF_ORIG_SOURCES);
this.menuitemSources.setAttribute("checked", showOrig);
},
/**
* Display the necessary copy context menu items depending on the clicked
* node and selection in the rule view.
*/
_enableCopyMenuItems: function(target) {
let win = this.doc.defaultView; let win = this.doc.defaultView;
// Copy selection. // Copy selection.
@ -1382,18 +1474,31 @@ CssRuleView.prototype = {
copy = false; copy = false;
} }
this.menuitemCopy.hidden = !copy;
this.menuitemCopyColor.hidden = !this._isColorPopup(); this.menuitemCopyColor.hidden = !this._isColorPopup();
this.menuitemCopyImageDataUrl.hidden = !this._isImageUrlPopup(); this.menuitemCopyImageDataUrl.hidden = !this._isImageUrlPopup();
this.menuitemCopy.disabled = !copy;
let showOrig = Services.prefs.getBoolPref(PREF_ORIG_SOURCES); this.menuitemCopyLocation.hidden = true;
this.menuitemSources.setAttribute("checked", showOrig); this.menuitemCopyPropertyDeclaration.hidden = true;
this.menuitemCopyPropertyName.hidden = true;
this.menuitemCopyPropertyValue.hidden = true;
this.menuitemCopySelector.hidden = true;
this.menuitemShowMdnDocs.hidden = !this.enableMdnDocsTooltip || this._clickedNodeInfo = this.getNodeInfo(target);
!this.doc.popupNode.parentNode
.classList.contains(PROPERTY_NAME_CLASS);
this.menuitemAddRule.disabled = this.inspector.selection.isAnonymousNode(); if (!this._clickedNodeInfo) {
return;
} else if (this._clickedNodeInfo.type == overlays.VIEW_NODE_PROPERTY_TYPE) {
this.menuitemCopyPropertyDeclaration.hidden = false;
this.menuitemCopyPropertyName.hidden = false;
} else if (this._clickedNodeInfo.type == overlays.VIEW_NODE_VALUE_TYPE) {
this.menuitemCopyPropertyDeclaration.hidden = false;
this.menuitemCopyPropertyValue.hidden = false;
} else if (this._clickedNodeInfo.type == overlays.VIEW_NODE_SELECTOR_TYPE) {
this.menuitemCopySelector.hidden = false;
} else if (this._clickedNodeInfo.type == overlays.VIEW_NODE_LOCATION_TYPE) {
this.menuitemCopyLocation.hidden = false;
}
}, },
/** /**
@ -1422,7 +1527,8 @@ CssRuleView.prototype = {
enabled: prop.enabled, enabled: prop.enabled,
overridden: prop.overridden, overridden: prop.overridden,
pseudoElement: prop.rule.pseudoElement, pseudoElement: prop.rule.pseudoElement,
sheetHref: prop.rule.domRule.href sheetHref: prop.rule.domRule.href,
textProperty: prop
}; };
} else if (classes.contains("ruleview-propertyvalue") && prop) { } else if (classes.contains("ruleview-propertyvalue") && prop) {
type = overlays.VIEW_NODE_VALUE_TYPE; type = overlays.VIEW_NODE_VALUE_TYPE;
@ -1432,7 +1538,8 @@ CssRuleView.prototype = {
enabled: prop.enabled, enabled: prop.enabled,
overridden: prop.overridden, overridden: prop.overridden,
pseudoElement: prop.rule.pseudoElement, pseudoElement: prop.rule.pseudoElement,
sheetHref: prop.rule.domRule.href sheetHref: prop.rule.domRule.href,
textProperty: prop
}; };
} else if (classes.contains("theme-link") && } else if (classes.contains("theme-link") &&
!classes.contains("ruleview-rule-source") && prop) { !classes.contains("ruleview-rule-source") && prop) {
@ -1444,12 +1551,19 @@ CssRuleView.prototype = {
enabled: prop.enabled, enabled: prop.enabled,
overridden: prop.overridden, overridden: prop.overridden,
pseudoElement: prop.rule.pseudoElement, pseudoElement: prop.rule.pseudoElement,
sheetHref: prop.rule.domRule.href sheetHref: prop.rule.domRule.href,
textProperty: prop
}; };
} else if (classes.contains("ruleview-selector-unmatched") || } else if (classes.contains("ruleview-selector-unmatched") ||
classes.contains("ruleview-selector-matched")) { classes.contains("ruleview-selector-matched") ||
classes.contains("ruleview-selector")) {
type = overlays.VIEW_NODE_SELECTOR_TYPE; type = overlays.VIEW_NODE_SELECTOR_TYPE;
value = node.textContent; value = node.offsetParent._ruleEditor.selectorText.textContent;
} else if (classes.contains("ruleview-rule-source")) {
type = overlays.VIEW_NODE_LOCATION_TYPE;
let ruleEditor = node.offsetParent._ruleEditor;
let rule = ruleEditor.rule;
value = (rule.sheet && rule.sheet.href) ? rule.sheet.href : rule.title;
} else { } else {
return null; return null;
} }
@ -1624,6 +1738,71 @@ CssRuleView.prototype = {
clipboardHelper.copyString(message); clipboardHelper.copyString(message);
}), }),
/**
* Copy the rule source location of the current clicked node.
*/
_onCopyLocation: function() {
if (!this._clickedNodeInfo) {
return;
}
clipboardHelper.copyString(this._clickedNodeInfo.value, this.doc);
},
/**
* Copy the rule property declaration of the current clicked node.
*/
_onCopyPropertyDeclaration: function() {
if (!this._clickedNodeInfo) {
return;
}
let textProp = this._clickedNodeInfo.value.textProperty;
clipboardHelper.copyString(textProp.stringifyProperty(), this.doc);
},
/**
* Copy the rule property name of the current clicked node.
*/
_onCopyPropertyName: function() {
if (!this._clickedNodeInfo) {
return;
}
clipboardHelper.copyString(this._clickedNodeInfo.value.property, this.doc);
},
/**
* Copy the rule property value of the current clicked node.
*/
_onCopyPropertyValue: function() {
if (!this._clickedNodeInfo) {
return;
}
clipboardHelper.copyString(this._clickedNodeInfo.value.value, this.doc);
},
/**
* Copy the rule of the current clicked node.
*/
_onCopyRule: function() {
let ruleEditor = this.doc.popupNode.parentNode.offsetParent._ruleEditor;
let rule = ruleEditor.rule;
clipboardHelper.copyString(rule.stringifyRule(), this.doc);
},
/**
* Copy the rule selector of the current clicked node.
*/
_onCopySelector: function() {
if (!this._clickedNodeInfo) {
return;
}
clipboardHelper.copyString(this._clickedNodeInfo.value, this.doc);
},
/** /**
* Toggle the original sources pref. * Toggle the original sources pref.
*/ */
@ -1831,16 +2010,43 @@ CssRuleView.prototype = {
this.menuitemCopyColor = null; this.menuitemCopyColor = null;
// Destroy Copy Data URI menuitem. // Destroy Copy Data URI menuitem.
this.menuitemCopyImageDataUrl.removeEventListener("command", this._onCopyImageDataUrl); this.menuitemCopyImageDataUrl.removeEventListener("command",
this._onCopyImageDataUrl);
this.menuitemCopyImageDataUrl = null; this.menuitemCopyImageDataUrl = null;
this.menuitemCopyLocation.removeEventListener("command",
this._onCopyLocation);
this.menuitemCopyLocation = null;
this.menuitemCopyPropertyDeclaration.removeEventListener("command",
this._onCopyPropertyDeclaration);
this.menuitemCopyPropertyDeclaration = null;
this.menuitemCopyPropertyName.removeEventListener("command",
this._onCopyPropertyName);
this.menuitemCopyPropertyName = null;
this.menuitemCopyPropertyValue.removeEventListener("command",
this._onCopyPropertyValue);
this.menuitemCopyPropertyValue = null;
this.menuitemCopyRule.removeEventListener("command",
this._onCopyRule);
this.menuitemCopyRule = null;
this.menuitemCopySelector.removeEventListener("command",
this._onCopySelector);
this.menuitemCopySelector = null;
this.menuitemSources.removeEventListener("command", this.menuitemSources.removeEventListener("command",
this._onToggleOrigSources); this._onToggleOrigSources);
this.menuitemSources = null; this.menuitemSources = null;
this._clickedNodeInfo = null;
// Destroy the context menu. // Destroy the context menu.
this._contextmenu.removeEventListener("popupshowing", this._contextmenu.removeEventListener("popupshowing",
this._contextMenuUpdate); this._contextMenuUpdate);
this._contextmenu.parentNode.removeChild(this._contextmenu); this._contextmenu.parentNode.removeChild(this._contextmenu);
this._contextmenu = null; this._contextmenu = null;
} }
@ -3628,8 +3834,12 @@ function createMenuItem(aMenu, aAttributes) {
let item = aMenu.ownerDocument.createElementNS(XUL_NS, "menuitem"); let item = aMenu.ownerDocument.createElementNS(XUL_NS, "menuitem");
item.setAttribute("label", _strings.GetStringFromName(aAttributes.label)); item.setAttribute("label", _strings.GetStringFromName(aAttributes.label));
item.setAttribute("accesskey",
_strings.GetStringFromName(aAttributes.accesskey)); if (aAttributes.accesskey) {
item.setAttribute("accesskey",
_strings.GetStringFromName(aAttributes.accesskey));
}
item.addEventListener("command", aAttributes.command); item.addEventListener("command", aAttributes.command);
if (aAttributes.type) { if (aAttributes.type) {
@ -3641,6 +3851,11 @@ function createMenuItem(aMenu, aAttributes) {
return item; return item;
} }
function createMenuSeparator(aMenu) {
let separator = aMenu.ownerDocument.createElementNS(XUL_NS, "menuseparator");
aMenu.appendChild(separator);
}
function setTimeout() { function setTimeout() {
let window = Services.appShell.hiddenDOMWindow; let window = Services.appShell.hiddenDOMWindow;
return window.setTimeout.apply(window, arguments); return window.setTimeout.apply(window, arguments);
@ -3795,6 +4010,10 @@ XPCOMUtils.defineLazyGetter(this, "clipboardHelper", function() {
.getService(Ci.nsIClipboardHelper); .getService(Ci.nsIClipboardHelper);
}); });
XPCOMUtils.defineLazyGetter(this, "osString", function() {
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
});
XPCOMUtils.defineLazyGetter(this, "_strings", function() { XPCOMUtils.defineLazyGetter(this, "_strings", function() {
return Services.strings.createBundle( return Services.strings.createBundle(
"chrome://global/locale/devtools/styleinspector.properties"); "chrome://global/locale/devtools/styleinspector.properties");

View File

@ -37,6 +37,7 @@ const VIEW_NODE_SELECTOR_TYPE = exports.VIEW_NODE_SELECTOR_TYPE = 1;
const VIEW_NODE_PROPERTY_TYPE = exports.VIEW_NODE_PROPERTY_TYPE = 2; const VIEW_NODE_PROPERTY_TYPE = exports.VIEW_NODE_PROPERTY_TYPE = 2;
const VIEW_NODE_VALUE_TYPE = exports.VIEW_NODE_VALUE_TYPE = 3; const VIEW_NODE_VALUE_TYPE = exports.VIEW_NODE_VALUE_TYPE = 3;
const VIEW_NODE_IMAGE_URL_TYPE = exports.VIEW_NODE_IMAGE_URL_TYPE = 4; const VIEW_NODE_IMAGE_URL_TYPE = exports.VIEW_NODE_IMAGE_URL_TYPE = 4;
const VIEW_NODE_LOCATION_TYPE = exports.VIEW_NODE_LOCATION_TYPE = 5;
/** /**
* Manages all highlighters in the style-inspector. * Manages all highlighters in the style-inspector.

View File

@ -9,6 +9,8 @@ support-files =
doc_content_stylesheet_linked.css doc_content_stylesheet_linked.css
doc_content_stylesheet_script.css doc_content_stylesheet_script.css
doc_content_stylesheet_xul.css doc_content_stylesheet_xul.css
doc_copystyles.css
doc_copystyles.html
doc_filter.html doc_filter.html
doc_frame_script.js doc_frame_script.js
doc_keyframeanimation.html doc_keyframeanimation.html
@ -76,6 +78,7 @@ skip-if = e10s # Bug 1039528: "inspect element" contextual-menu doesn't work wit
[browser_ruleview_context-menu-show-mdn-docs-01.js] [browser_ruleview_context-menu-show-mdn-docs-01.js]
[browser_ruleview_context-menu-show-mdn-docs-02.js] [browser_ruleview_context-menu-show-mdn-docs-02.js]
[browser_ruleview_context-menu-show-mdn-docs-03.js] [browser_ruleview_context-menu-show-mdn-docs-03.js]
[browser_ruleview_copy_styles.js]
[browser_ruleview_cubicbezier-appears-on-swatch-click.js] [browser_ruleview_cubicbezier-appears-on-swatch-click.js]
[browser_ruleview_cubicbezier-commit-on-ENTER.js] [browser_ruleview_cubicbezier-commit-on-ENTER.js]
[browser_ruleview_cubicbezier-revert-on-ESC.js] [browser_ruleview_cubicbezier-revert-on-ESC.js]

View File

@ -0,0 +1,246 @@
/* 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";
/**
* Tests the behaviour of the copy styles context menu items in the rule
* view
*/
XPCOMUtils.defineLazyGetter(this, "osString", function() {
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
});
let TEST_URI = TEST_URL_ROOT + "doc_copystyles.html";
add_task(function*() {
yield addTab(TEST_URI);
let { inspector, view } = yield openRuleView();
yield selectNode("#testid", inspector);
let ruleEditor = getRuleViewRuleEditor(view, 1);
let data = [
{
desc: "Test Copy Property Name",
node: ruleEditor.rule.textProps[0].editor.nameSpan,
menuItem: view.menuitemCopyPropertyName,
expectedPattern: "color",
hidden: {
copyLocation: true,
copyPropertyDeclaration: false,
copyPropertyName: false,
copyPropertyValue: true,
copySelector: true,
copyRule: false
}
},
{
desc: "Test Copy Property Value",
node: ruleEditor.rule.textProps[2].editor.valueSpan,
menuItem: view.menuitemCopyPropertyValue,
expectedPattern: "12px",
hidden: {
copyLocation: true,
copyPropertyDeclaration: false,
copyPropertyName: true,
copyPropertyValue: false,
copySelector: true,
copyRule: false
}
},
{
desc: "Test Copy Property Declaration",
node: ruleEditor.rule.textProps[2].editor.nameSpan,
menuItem: view.menuitemCopyPropertyDeclaration,
expectedPattern: "font-size: 12px;",
hidden: {
copyLocation: true,
copyPropertyDeclaration: false,
copyPropertyName: false,
copyPropertyValue: true,
copySelector: true,
copyRule: false
}
},
{
desc: "Test Copy Rule",
node: ruleEditor.rule.textProps[2].editor.nameSpan,
menuItem: view.menuitemCopyRule,
expectedPattern: "#testid {[\\r\\n]+" +
"\tcolor: #F00;[\\r\\n]+" +
"\tbackground-color: #00F;[\\r\\n]+" +
"\tfont-size: 12px;[\\r\\n]+" +
"}",
hidden: {
copyLocation: true,
copyPropertyDeclaration: false,
copyPropertyName: false,
copyPropertyValue: true,
copySelector: true,
copyRule: false
}
},
{
desc: "Test Copy Selector",
node: ruleEditor.selectorText,
menuItem: view.menuitemCopySelector,
expectedPattern: "html, body, #testid",
hidden: {
copyLocation: true,
copyPropertyDeclaration: true,
copyPropertyName: true,
copyPropertyValue: true,
copySelector: false,
copyRule: false
}
},
{
desc: "Test Copy Location",
node: ruleEditor.source,
menuItem: view.menuitemCopyLocation,
expectedPattern: "http://example.com/browser/browser/devtools/" +
"styleinspector/test/doc_copystyles.css",
hidden: {
copyLocation: false,
copyPropertyDeclaration: true,
copyPropertyName: true,
copyPropertyValue: true,
copySelector: true,
copyRule: false
}
},
{
setup: function*() {
yield disableProperty(view);
},
desc: "Test Copy Rule with Disabled Property",
node: ruleEditor.rule.textProps[2].editor.nameSpan,
menuItem: view.menuitemCopyRule,
expectedPattern: "#testid {[\\r\\n]+" +
"\t\/\\* color: #F00; \\*\/[\\r\\n]+" +
"\tbackground-color: #00F;[\\r\\n]+" +
"\tfont-size: 12px;[\\r\\n]+" +
"}",
hidden: {
copyLocation: true,
copyPropertyDeclaration: false,
copyPropertyName: false,
copyPropertyValue: true,
copySelector: true,
copyRule: false
}
},
{
desc: "Test Copy Property Declaration with Disabled Property",
node: ruleEditor.rule.textProps[0].editor.nameSpan,
menuItem: view.menuitemCopyPropertyDeclaration,
expectedPattern: "\/\\* color: #F00; \\*\/",
hidden: {
copyLocation: true,
copyPropertyDeclaration: false,
copyPropertyName: false,
copyPropertyValue: true,
copySelector: true,
copyRule: false
}
},
];
for (let { setup, desc, node, menuItem, expectedPattern, hidden } of data) {
if (setup) {
yield setup();
}
info(desc);
yield checkCopyStyle(view, node, menuItem, expectedPattern, hidden);
}
});
function* checkCopyStyle(view, node, menuItem, expectedPattern, hidden) {
let win = view.doc.defaultView;
let onPopup = once(view._contextmenu, "popupshown");
EventUtils.synthesizeMouseAtCenter(node,
{button: 2, type: "contextmenu"}, win);
yield onPopup;
is(view.menuitemCopy.hidden, true, "Copy hidden is as expected: true");
is(view.menuitemCopyLocation.hidden,
hidden.copyLocation,
"Copy Location hidden attribute is as expected: " +
hidden.copyLocation);
is(view.menuitemCopyPropertyDeclaration.hidden,
hidden.copyPropertyDeclaration,
"Copy Property Declaration hidden attribute is as expected: " +
hidden.copyPropertyDeclaration);
is(view.menuitemCopyPropertyName.hidden,
hidden.copyPropertyName,
"Copy Property Name hidden attribute is as expected: " +
hidden.copyPropertyName);
is(view.menuitemCopyPropertyValue.hidden,
hidden.copyPropertyValue,
"Copy Property Value hidden attribute is as expected: " +
hidden.copyPropertyValue);
is(view.menuitemCopySelector.hidden,
hidden.copySelector,
"Copy Selector hidden attribute is as expected: " +
hidden.copySelector);
is(view.menuitemCopyRule.hidden,
hidden.copyRule,
"Copy Rule hidden attribute is as expected: " +
hidden.copyRule);
try {
yield waitForClipboard(() => menuItem.click(),
() => checkClipboardData(expectedPattern));
} catch(e) {
failedClipboard(expectedPattern);
}
view._contextmenu.hidePopup();
}
function* disableProperty(view) {
let ruleEditor = getRuleViewRuleEditor(view, 1);
let propEditor = ruleEditor.rule.textProps[0].editor;
info("Disabling a property");
propEditor.enable.click();
yield ruleEditor.rule._applyingModifications;
}
function checkClipboardData(expectedPattern) {
let actual = SpecialPowers.getClipboardData("text/unicode");
let expectedRegExp = new RegExp(expectedPattern, "g");
return expectedRegExp.test(actual);
}
function failedClipboard(expectedPattern) {
// Format expected text for comparison
let terminator = osString == "WINNT" ? "\r\n" : "\n";
expectedPattern = expectedPattern.replace(/\[\\r\\n\][+*]/g, terminator);
expectedPattern = expectedPattern.replace(/\\\(/g, "(");
expectedPattern = expectedPattern.replace(/\\\)/g, ")");
let actual = SpecialPowers.getClipboardData("text/unicode");
// Trim the right hand side of our strings. This is because expectedPattern
// accounts for windows sometimes adding a newline to our copied data.
expectedPattern = expectedPattern.trimRight();
actual = actual.trimRight();
ok(false, "Clipboard text does not match expected " +
"results (escaped for accurate comparison):\n");
info("Actual: " + escape(actual));
info("Expected: " + escape(expectedPattern));
}

View File

@ -33,8 +33,7 @@ add_task(function*() {
'</div>'; '</div>';
content.document.title = "Rule view context menu test"; content.document.title = "Rule view context menu test";
info("Opening the computed view"); let {inspector, view} = yield openRuleView();
let {toolbox, inspector, view} = yield openRuleView();
info("Selecting the test node"); info("Selecting the test node");
yield selectNode("div", inspector); yield selectNode("div", inspector);
@ -43,17 +42,18 @@ add_task(function*() {
yield checkSelectAll(view); yield checkSelectAll(view);
}); });
function checkCopySelection(view) { function* checkCopySelection(view) {
info("Testing selection copy"); info("Testing selection copy");
let contentDoc = view.doc; let contentDoc = view.doc;
let win = contentDoc.defaultView;
let prop = contentDoc.querySelector(".ruleview-property"); let prop = contentDoc.querySelector(".ruleview-property");
let values = contentDoc.querySelectorAll(".ruleview-propertyvaluecontainer"); let values = contentDoc.querySelectorAll(".ruleview-propertyvaluecontainer");
let range = contentDoc.createRange(); let range = contentDoc.createRange();
range.setStart(prop, 0); range.setStart(prop, 0);
range.setEnd(values[4], 2); range.setEnd(values[4], 2);
let selection = view.doc.defaultView.getSelection().addRange(range); view.doc.defaultView.getSelection().addRange(range);
info("Checking that _Copy() returns the correct clipboard value"); info("Checking that _Copy() returns the correct clipboard value");
@ -65,19 +65,28 @@ function checkCopySelection(view) {
"html {[\\r\\n]+" + "html {[\\r\\n]+" +
" color: #000;[\\r\\n]*"; " color: #000;[\\r\\n]*";
return waitForClipboard(() => { let onPopup = once(view._contextmenu, "popupshown");
fireCopyEvent(prop); EventUtils.synthesizeMouseAtCenter(prop,
}, () => { {button: 2, type: "contextmenu"}, win);
return checkClipboardData(expectedPattern); yield onPopup;
}).then(() => {}, () => {
ok(!view.menuitemCopy.hidden, "Copy menu item is not hidden as expected");
try {
yield waitForClipboard(() => view.menuitemCopy.click(),
() => checkClipboardData(expectedPattern));
} catch(e) {
failedClipboard(expectedPattern); failedClipboard(expectedPattern);
}); }
view._contextmenu.hidePopup();
} }
function checkSelectAll(view) { function* checkSelectAll(view) {
info("Testing select-all copy"); info("Testing select-all copy");
let contentDoc = view.doc; let contentDoc = view.doc;
let win = contentDoc.defaultView;
let prop = contentDoc.querySelector(".ruleview-property"); let prop = contentDoc.querySelector(".ruleview-property");
info("Checking that _SelectAll() then copy returns the correct clipboard value"); info("Checking that _SelectAll() then copy returns the correct clipboard value");
@ -93,13 +102,21 @@ function checkSelectAll(view) {
" color: #000;[\\r\\n]+" + " color: #000;[\\r\\n]+" +
"}[\\r\\n]*"; "}[\\r\\n]*";
return waitForClipboard(() => { let onPopup = once(view._contextmenu, "popupshown");
fireCopyEvent(prop); EventUtils.synthesizeMouseAtCenter(prop,
}, () => { {button: 2, type: "contextmenu"}, win);
return checkClipboardData(expectedPattern); yield onPopup;
}).then(() => {}, () => {
ok(!view.menuitemCopy.hidden, "Copy menu item is not hidden as expected");
try {
yield waitForClipboard(() => view.menuitemCopy.click(),
() => checkClipboardData(expectedPattern));
} catch(e) {
failedClipboard(expectedPattern); failedClipboard(expectedPattern);
}); }
view._contextmenu.hidePopup();
} }
function checkClipboardData(expectedPattern) { function checkClipboardData(expectedPattern) {

View File

@ -0,0 +1,9 @@
/* 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/. */
html, body, #testid {
color: #F00;
background-color: #00F;
font-size: 12px;
}

View File

@ -0,0 +1,11 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<head>
<title>Test case for copying stylesheet in rule-view</title>
<link rel="stylesheet" type="text/css" href="doc_copystyles.css"/>
</head>
<body>
<div id='testid'>Styled Node</div>
</body>
</html>

View File

@ -112,7 +112,7 @@ styleinspector.copyImageDataUrlError=Failed to copy image Data-URL
# LOCALIZATION NOTE (ruleView.contextmenu.showOrigSources): Text displayed in the rule view # LOCALIZATION NOTE (ruleView.contextmenu.showOrigSources): Text displayed in the rule view
# context menu. # context menu.
ruleView.contextmenu.showOrigSources=Show original sources ruleView.contextmenu.showOrigSources=Show Original Sources
# LOCALIZATION NOTE (ruleView.contextmenu.showOrigSources.accessKey): Access key for # LOCALIZATION NOTE (ruleView.contextmenu.showOrigSources.accessKey): Access key for
# the rule view context menu "Show original sources" entry. # the rule view context menu "Show original sources" entry.
@ -120,7 +120,7 @@ ruleView.contextmenu.showOrigSources.accessKey=O
# LOCALIZATION NOTE (ruleView.contextmenu.showMdnDocs): Text displayed in the rule view # LOCALIZATION NOTE (ruleView.contextmenu.showMdnDocs): Text displayed in the rule view
# context menu to display docs from MDN for an item. # context menu to display docs from MDN for an item.
ruleView.contextmenu.showMdnDocs=Show MDN docs ruleView.contextmenu.showMdnDocs=Show MDN Docs
# LOCALIZATION NOTE (ruleView.contextmenu.showMdnDocs.accessKey): Access key for # LOCALIZATION NOTE (ruleView.contextmenu.showMdnDocs.accessKey): Access key for
# the rule view context menu "Show MDN docs" entry. # the rule view context menu "Show MDN docs" entry.
@ -129,7 +129,7 @@ ruleView.contextmenu.showMdnDocs.accessKey=D
# LOCALIZATION NOTE (ruleView.contextmenu.addNewRule): Text displayed in the # LOCALIZATION NOTE (ruleView.contextmenu.addNewRule): Text displayed in the
# rule view context menu for adding a new rule to the element. # rule view context menu for adding a new rule to the element.
# This should match addRuleButton.tooltip in styleinspector.dtd # This should match addRuleButton.tooltip in styleinspector.dtd
ruleView.contextmenu.addNewRule=Add new rule ruleView.contextmenu.addNewRule=Add New Rule
# LOCALIZATION NOTE (ruleView.contextmenu.addRule.accessKey): Access key for # LOCALIZATION NOTE (ruleView.contextmenu.addRule.accessKey): Access key for
# the rule view context menu "Add rule" entry. # the rule view context menu "Add rule" entry.
@ -137,7 +137,7 @@ ruleView.contextmenu.addNewRule.accessKey=R
# LOCALIZATION NOTE (computedView.contextmenu.selectAll): Text displayed in the # LOCALIZATION NOTE (computedView.contextmenu.selectAll): Text displayed in the
# computed view context menu. # computed view context menu.
computedView.contextmenu.selectAll=Select all computedView.contextmenu.selectAll=Select All
# LOCALIZATION NOTE (computedView.contextmenu.selectAll.accessKey): Access key for # LOCALIZATION NOTE (computedView.contextmenu.selectAll.accessKey): Access key for
# the computed view context menu "Select all" entry. # the computed view context menu "Select all" entry.
@ -150,3 +150,27 @@ computedView.contextmenu.copy=Copy
# LOCALIZATION NOTE (computedView.contextmenu.copy.accessKey): Access key for # LOCALIZATION NOTE (computedView.contextmenu.copy.accessKey): Access key for
# the computed view context menu "Copy" entry. # the computed view context menu "Copy" entry.
computedView.contextmenu.copy.accessKey=C computedView.contextmenu.copy.accessKey=C
# LOCALIZATION NOTE (ruleView.contextmenu.copyLocation): Text displayed in the
# rule view context menu for copying the source location.
ruleView.contextmenu.copyLocation=Copy Location
# LOCALIZATION NOTE (ruleView.contextmenu.copyPropertyDeclaration): Text
# displayed in the rule view context menu for copying the property declaration.
ruleView.contextmenu.copyPropertyDeclaration=Copy Property Declaration
# LOCALIZATION NOTE (ruleView.contextmenu.copyPropertyName): Text displayed in
# the rule view context menu for copying the property name.
ruleView.contextmenu.copyPropertyName=Copy Property Name
# LOCALIZATION NOTE (ruleView.contextmenu.copyPropertyValue): Text displayed in
# the rule view context menu for copying the property value.
ruleView.contextmenu.copyPropertyValue=Copy Property Value
# LOCALIZATION NOTE (ruleView.contextmenu.copyRule): Text displayed in the
# rule view context menu for copying the rule.
ruleView.contextmenu.copyRule=Copy Rule
# LOCALIZATION NOTE (ruleView.contextmenu.copySelector): Text displayed in the
# rule view context menu for copying the selector.
ruleView.contextmenu.copySelector=Copy Selector