diff --git a/browser/devtools/highlighter/inspector.jsm b/browser/devtools/highlighter/inspector.jsm index 361fd38621e..254f1f0737e 100644 --- a/browser/devtools/highlighter/inspector.jsm +++ b/browser/devtools/highlighter/inspector.jsm @@ -939,27 +939,6 @@ InspectorUI.prototype = { this.cssRuleViewBoundCSSLinkClicked = this.ruleViewCSSLinkClicked.bind(this); this.ruleView.element.addEventListener("CssRuleViewCSSLinkClicked", this.cssRuleViewBoundCSSLinkClicked); - this.cssRuleViewBoundMouseDown = this.ruleViewMouseDown.bind(this); - this.ruleView.element.addEventListener("mousedown", - this.cssRuleViewBoundMouseDown); - this.cssRuleViewBoundMouseUp = this.ruleViewMouseUp.bind(this); - this.ruleView.element.addEventListener("mouseup", - this.cssRuleViewBoundMouseUp); - this.cssRuleViewBoundMouseMove = this.ruleViewMouseMove.bind(this); - this.cssRuleViewBoundMenuUpdate = this.ruleViewMenuUpdate.bind(this); - - this.cssRuleViewBoundCopy = this.ruleViewCopy.bind(this); - iframe.addEventListener("copy", this.cssRuleViewBoundCopy); - - this.cssRuleViewBoundCopyRule = this.ruleViewCopyRule.bind(this); - this.cssRuleViewBoundCopyDeclaration = - this.ruleViewCopyDeclaration.bind(this); - this.cssRuleViewBoundCopyProperty = this.ruleViewCopyProperty.bind(this); - this.cssRuleViewBoundCopyPropertyValue = - this.ruleViewCopyPropertyValue.bind(this); - - // Add the rule view's context menu. - this.ruleViewAddContextMenu(); doc.documentElement.appendChild(this.ruleView.element); this.ruleView.highlight(this.selection); @@ -1050,364 +1029,24 @@ InspectorUI.prototype = { } }, - /** - * This is the mousedown handler for the rule view. We use it to track whether - * text is currently getting selected. - * . - * @param aEvent The event object - */ - ruleViewMouseDown: function IUI_ruleViewMouseDown(aEvent) - { - this.ruleView.element.addEventListener("mousemove", - this.cssRuleViewBoundMouseMove); - }, - - /** - * This is the mouseup handler for the rule view. We use it to track whether - * text is currently getting selected. - * . - * @param aEvent The event object - */ - ruleViewMouseUp: function IUI_ruleViewMouseUp(aEvent) - { - this.ruleView.element.removeEventListener("mousemove", - this.cssRuleViewBoundMouseMove); - this.ruleView._selectionMode = false; - }, - - /** - * This is the mousemove handler for the rule view. We use it to track whether - * text is currently getting selected. - * . - * @param aEvent The event object - */ - ruleViewMouseMove: function IUI_ruleViewMouseMove(aEvent) - { - this.ruleView._selectionMode = true; - }, - - /** - * Add a context menu to the rule view. - */ - ruleViewAddContextMenu: function IUI_ruleViewAddContextMenu() - { - let iframe = this.getToolIframe(this.ruleViewObject); - let popupSet = this.chromeDoc.getElementById("mainPopupSet"); - let menu = this.chromeDoc.createElement("menupopup"); - menu.addEventListener("popupshowing", this.cssRuleViewBoundMenuUpdate); - menu.id = "rule-view-context-menu"; - - // Copy selection - let label = styleInspectorStrings - .GetStringFromName("rule.contextmenu.copyselection"); - let accessKey = styleInspectorStrings - .GetStringFromName("rule.contextmenu.copyselection.accesskey"); - let item = this.chromeDoc.createElement("menuitem"); - item.id = "rule-view-copy"; - item.setAttribute("label", label); - item.setAttribute("accesskey", accessKey); - item.addEventListener("command", this.cssRuleViewBoundCopy); - menu.appendChild(item); - - // Copy rule - label = styleInspectorStrings. - GetStringFromName("rule.contextmenu.copyrule"); - accessKey = styleInspectorStrings. - GetStringFromName("rule.contextmenu.copyrule.accesskey"); - item = this.chromeDoc.createElement("menuitem"); - item.id = "rule-view-copy-rule"; - item.setAttribute("label", label); - item.setAttribute("accesskey", accessKey); - item.addEventListener("command", this.cssRuleViewBoundCopyRule); - menu.appendChild(item); - - // Copy declaration - label = styleInspectorStrings. - GetStringFromName("rule.contextmenu.copydeclaration"); - accessKey = styleInspectorStrings. - GetStringFromName("rule.contextmenu.copydeclaration.accesskey"); - item = this.chromeDoc.createElement("menuitem"); - item.id = "rule-view-copy-declaration"; - item.setAttribute("label", label); - item.setAttribute("accesskey", accessKey); - item.addEventListener("command", this.cssRuleViewBoundCopyDeclaration); - menu.appendChild(item); - - // Copy property name - label = styleInspectorStrings. - GetStringFromName("rule.contextmenu.copyproperty"); - accessKey = styleInspectorStrings. - GetStringFromName("rule.contextmenu.copyproperty.accesskey"); - item = this.chromeDoc.createElement("menuitem"); - item.id = "rule-view-copy-property"; - item.setAttribute("label", label); - item.setAttribute("accesskey", accessKey); - item.addEventListener("command", this.cssRuleViewBoundCopyProperty); - menu.appendChild(item); - - // Copy property value - label = styleInspectorStrings. - GetStringFromName("rule.contextmenu.copypropertyvalue"); - accessKey = styleInspectorStrings. - GetStringFromName("rule.contextmenu.copypropertyvalue.accesskey"); - item = this.chromeDoc.createElement("menuitem"); - item.id = "rule-view-copy-property-value"; - item.setAttribute("label", label); - item.setAttribute("accesskey", accessKey); - item.addEventListener("command", this.cssRuleViewBoundCopyPropertyValue); - menu.appendChild(item); - - popupSet.appendChild(menu); - - iframe.setAttribute("context", menu.id); - }, - - /** - * Update the rule view's context menu by disabling irrelevant menuitems and - * enabling relevant ones. - * - * @param aEvent The event object - */ - ruleViewMenuUpdate: function IUI_ruleViewMenuUpdate(aEvent) - { - let iframe = this.getToolIframe(this.ruleViewObject); - let win = iframe.contentWindow; - - // Copy selection. - let disable = win.getSelection().isCollapsed; - let menuitem = this.chromeDoc.getElementById("rule-view-copy"); - menuitem.disabled = disable; - - // Copy property, copy property name & copy property value. - let node = this.chromeDoc.popupNode; - if (!node.classList.contains("ruleview-property") && - !node.classList.contains("ruleview-computed")) { - while (node = node.parentElement) { - if (node.classList.contains("ruleview-property") || - node.classList.contains("ruleview-computed")) { - break; - } - } - } - let disablePropertyItems = !node || (node && - !node.classList.contains("ruleview-property") && - !node.classList.contains("ruleview-computed")); - - menuitem = this.chromeDoc.querySelector("#rule-view-copy-declaration"); - menuitem.disabled = disablePropertyItems; - menuitem = this.chromeDoc.querySelector("#rule-view-copy-property"); - menuitem.disabled = disablePropertyItems; - menuitem = this.chromeDoc.querySelector("#rule-view-copy-property-value"); - menuitem.disabled = disablePropertyItems; - }, - - /** - * Copy selected text from the rule view. - * - * @param aEvent The event object - */ - ruleViewCopy: function IUI_ruleViewCopy(aEvent) - { - let iframe = this.getToolIframe(this.ruleViewObject); - let win = iframe.contentWindow; - let text = win.getSelection().toString(); - - // Remove any double newlines. - text = text.replace(/(\r?\n)\r?\n/g, "$1"); - - // Remove "inline" - let inline = styleInspectorStrings.GetStringFromName("rule.sourceInline"); - let rx = new RegExp("^" + inline + "\\r?\\n?", "g"); - text = text.replace(rx, ""); - - // Remove file:line - text = text.replace(/[\w\.]+:\d+(\r?\n)/g, "$1"); - - // Remove inherited from: line - let inheritedFrom = styleInspectorStrings - .GetStringFromName("rule.inheritedSource"); - inheritedFrom = inheritedFrom.replace(/\s%S\s\(%S\)/g, ""); - rx = new RegExp("(\r?\n)" + inheritedFrom + ".*", "g"); - text = text.replace(rx, "$1"); - - clipboardHelper.copyString(text); - - if (aEvent) { - aEvent.preventDefault(); - } - }, - - /** - * Copy a rule from the rule view. - * - * @param aEvent The event object - */ - ruleViewCopyRule: function IUI_ruleViewCopyRule(aEvent) - { - let node = this.chromeDoc.popupNode; - if (node.className != "ruleview-code") { - if (node.className == "ruleview-rule-source") { - node = node.nextElementSibling; - } else { - while (node = node.parentElement) { - if (node.className == "ruleview-code") { - break; - } - } - } - } - - if (node.className == "ruleview-code") { - // We need to strip expanded properties from the node because we use - // node.textContent below, which also gets text from hidden nodes. The - // simplest way to do this is to clone the node and remove them from the - // clone. - node = node.cloneNode(); - let computed = node.querySelector(".ruleview-computedlist"); - if (computed) { - computed.parentNode.removeChild(computed); - } - let autosizer = node.querySelector(".autosizer"); - if (autosizer) { - autosizer.parentNode.removeChild(autosizer); - } - } - - let text = node.textContent; - - // Format the rule - if (osString == "WINNT") { - text = text.replace(/{/g, "{\r\n "); - text = text.replace(/;/g, ";\r\n "); - text = text.replace(/\s*}/g, "\r\n}"); - } else { - text = text.replace(/{/g, "{\n "); - text = text.replace(/;/g, ";\n "); - text = text.replace(/\s*}/g, "\n}"); - } - - clipboardHelper.copyString(text); - }, - - /** - * Copy a declaration from the rule view. - * - * @param aEvent The event object - */ - ruleViewCopyDeclaration: function IUI_ruleViewCopyDeclaration(aEvent) - { - let node = this.chromeDoc.popupNode; - if (!node.classList.contains("ruleview-property") && - !node.classList.contains("ruleview-computed")) { - while (node = node.parentElement) { - if (node.classList.contains("ruleview-property") || - node.classList.contains("ruleview-computed")) { - break; - } - } - } - - // We need to strip expanded properties from the node because we use - // node.textContent below, which also gets text from hidden nodes. The - // simplest way to do this is to clone the node and remove them from the - // clone. - node = node.cloneNode(); - let computed = node.querySelector(".ruleview-computedlist"); - if (computed) { - computed.parentNode.removeChild(computed); - } - clipboardHelper.copyString(node.textContent); - }, - - /** - * Copy a property name from the rule view. - * - * @param aEvent The event object - */ - ruleViewCopyProperty: function IUI_ruleViewCopyProperty(aEvent) - { - let node = this.chromeDoc.popupNode; - - if (!node.classList.contains("ruleview-propertyname")) { - node = node.querySelector(".ruleview-propertyname"); - } - - if (node) { - clipboardHelper.copyString(node.textContent); - } - }, - - /** - * Copy a property value from the rule view. - * - * @param aEvent The event object - */ - ruleViewCopyPropertyValue: function IUI_ruleViewCopyPropertyValue(aEvent) - { - let node = this.chromeDoc.popupNode; - - if (!node.classList.contains("ruleview-propertyvalue")) { - node = node.querySelector(".ruleview-propertyvalue"); - } - - if (node) { - clipboardHelper.copyString(node.textContent); - } - }, - /** * Destroy the rule view. */ destroyRuleView: function IUI_destroyRuleView() { - let iframe = this.getToolIframe(this.ruleViewObject); - iframe.removeEventListener("copy", this.cssRuleViewBoundCopy); - iframe.parentNode.removeChild(iframe); - if (this.ruleView) { - let menu = this.chromeDoc.querySelector("#rule-view-context-menu"); - if (menu) { - // Copy - let menuitem = this.chromeDoc.querySelector("#rule-view-copy"); - menuitem.removeEventListener("command", this.cssRuleViewBoundCopy); - - // Copy rule - menuitem = this.chromeDoc.querySelector("#rule-view-copy-rule"); - menuitem.removeEventListener("command", this.cssRuleViewBoundCopyRule); - - // Copy property - menuitem = this.chromeDoc.querySelector("#rule-view-copy-declaration"); - menuitem.removeEventListener("command", - this.cssRuleViewBoundCopyDeclaration); - - // Copy property name - menuitem = this.chromeDoc.querySelector("#rule-view-copy-property"); - menuitem.removeEventListener("command", - this.cssRuleViewBoundCopyProperty); - - // Copy property value - menuitem = this.chromeDoc.querySelector("#rule-view-copy-property-value"); - menuitem.removeEventListener("command", - this.cssRuleViewBoundCopyPropertyValue); - - menu.removeEventListener("popupshowing", this.cssRuleViewBoundMenuUpdate); - menu.parentNode.removeChild(menu); - } - this.ruleView.element.removeEventListener("CssRuleViewChanged", this.boundRuleViewChanged); this.ruleView.element.removeEventListener("CssRuleViewCSSLinkClicked", this.cssRuleViewBoundCSSLinkClicked); - this.ruleView.element.removeEventListener("mousedown", - this.cssRuleViewBoundMouseDown); - this.ruleView.element.removeEventListener("mouseup", - this.cssRuleViewBoundMouseUp); - this.ruleView.element.removeEventListener("mousemove", - this.cssRuleViewBoundMouseMove); - delete boundRuleViewChanged; - this.ruleView.clear(); + delete this.boundRuleViewChanged; + delete this.cssRuleViewBoundCSSLinkClicked; + this.ruleView.destroy(); delete this.ruleView; } + + let iframe = this.getToolIframe(this.ruleViewObject); + iframe.parentNode.removeChild(iframe); }, ///////////////////////////////////////////////////////////////////////// @@ -2631,12 +2270,3 @@ XPCOMUtils.defineLazyGetter(this, "clipboardHelper", function() { return Cc["@mozilla.org/widget/clipboardhelper;1"]. getService(Ci.nsIClipboardHelper); }); - -XPCOMUtils.defineLazyGetter(this, "styleInspectorStrings", function() { - return Services.strings.createBundle( - "chrome://browser/locale/devtools/styleinspector.properties"); -}); - -XPCOMUtils.defineLazyGetter(this, "osString", function() { - return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS; -}); diff --git a/browser/devtools/highlighter/test/browser_inspector_duplicate_ruleview.js b/browser/devtools/highlighter/test/browser_inspector_duplicate_ruleview.js index d51d1849547..d5ab35345b6 100644 --- a/browser/devtools/highlighter/test/browser_inspector_duplicate_ruleview.js +++ b/browser/devtools/highlighter/test/browser_inspector_duplicate_ruleview.js @@ -90,7 +90,9 @@ function inspectorFocusTab1() is(InspectorUI.selection, div, "selection matches the div element"); ok(InspectorUI.isSidebarOpen, "sidebar is open"); ok(InspectorUI.isRuleViewOpen(), "rule view is open"); - is(InspectorUI.ruleView.doc.documentElement.children.length, 1, "RuleView elements.length == 1"); + + // The rule view element plus its popupSet + is(InspectorUI.ruleView.doc.documentElement.children.length, 2, "RuleView elements.length == 2"); requestLongerTimeout(4); executeSoon(function() { diff --git a/browser/devtools/styleinspector/CssRuleView.jsm b/browser/devtools/styleinspector/CssRuleView.jsm index 09df37550ca..62e2e3dc8f3 100644 --- a/browser/devtools/styleinspector/CssRuleView.jsm +++ b/browser/devtools/styleinspector/CssRuleView.jsm @@ -64,6 +64,7 @@ const CSS_PROP_RE = /\s*([^:\s]*)\s*:\s*(.*?)\s*(?:! (important))?;?$/; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource:///modules/devtools/CssLogic.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); var EXPORTED_SYMBOLS = ["CssRuleView", "_ElementStyle", @@ -699,12 +700,55 @@ function CssRuleView(aDoc, aStore) this.element.setAttribute("tabindex", "0"); this.element.classList.add("ruleview"); this.element.flex = 1; + this._selectionMode = false; + + this._boundMouseDown = this._onMouseDown.bind(this); + this.element.addEventListener("mousedown", + this._boundMouseDown); + this._boundMouseUp = this._onMouseUp.bind(this); + this.element.addEventListener("mouseup", + this._boundMouseUp); + this._boundMouseMove = this._onMouseMove.bind(this); + + this._boundCopy = this._onCopy.bind(this); + this.element.addEventListener("copy", this._boundCopy); + + this._createContextMenu(); } CssRuleView.prototype = { // The element that we're inspecting. _viewedElement: null, + destroy: function CssRuleView_destroy() + { + this.clear(); + + this.element.removeEventListener("copy", this._boundCopy); + this._copyItem.removeEventListener("command", this._boundCopy); + delete this._boundCopy; + + this._ruleItem.removeEventListener("command", this._boundCopyRule); + delete this._boundCopyRule; + + this._declarationItem.removeEventListener("command", this._boundCopyDeclaration); + delete this._boundCopyDeclaration; + + this._propertyItem.removeEventListener("command", this._boundCopyProperty); + delete this._boundCopyProperty; + + this._propertyValueItem.removeEventListener("command", this._boundCopyPropertyValue); + delete this._boundCopyPropertyValue; + + this._contextMenu.removeEventListener("popupshowing", this._boundMenuUpdate); + delete this._boundMenuUpdate; + delete this._contextMenu; + + if (this.element.parentNode) { + this.element.parentNode.removeChild(this.element); + } + }, + /** * Update the highlighted element. * @@ -762,7 +806,7 @@ CssRuleView.prototype = { this._clearRules(); this._elementStyle.populate(); this._createEditors(); - }, + }, /** * Clear the rules. @@ -813,6 +857,262 @@ CssRuleView.prototype = { this.element.appendChild(editor.element); } }, + + /** + * Add a context menu to the rule view. + */ + _createContextMenu: function CssRuleView_createContextMenu() + { + let popupSet = this.doc.createElement("popupset"); + this.doc.documentElement.appendChild(popupSet); + + let menu = this.doc.createElement("menupopup"); + menu.id = "rule-view-context-menu"; + + this._boundMenuUpdate = this._onMenuUpdate.bind(this); + menu.addEventListener("popupshowing", this._boundMenuUpdate); + + // Copy selection + this._copyItem = createMenuItem(menu, { + label: "rule.contextmenu.copyselection", + accesskey: "rule.contextmenu.copyselection.accesskey", + command: this._boundCopy + }); + + // Copy rule + this._boundCopyRule = this._onCopyRule.bind(this); + this._ruleItem = createMenuItem(menu, { + label: "rule.contextmenu.copyrule", + accesskey: "rule.contextmenu.copyrule.accesskey", + command: this._boundCopyRule + }); + + // Copy declaration + this._boundCopyDeclaration = this._onCopyDeclaration.bind(this); + this._declarationItem = createMenuItem(menu, { + label: "rule.contextmenu.copydeclaration", + accesskey: "rule.contextmenu.copydeclaration.accesskey", + command: this._boundCopyDeclaration + }); + + this._boundCopyProperty = this._onCopyProperty.bind(this); + this._propertyItem = createMenuItem(menu, { + label: "rule.contextmenu.copyproperty", + accesskey: "rule.contextmenu.copyproperty.accesskey", + command: this._boundCopyProperty + }); + + this._boundCopyPropertyValue = this._onCopyPropertyValue.bind(this); + this._propertyValueItem = createMenuItem(menu,{ + label: "rule.contextmenu.copypropertyvalue", + accesskey: "rule.contextmenu.copypropertyvalue.accesskey", + command: this._boundCopyPropertyValue + }); + + popupSet.appendChild(menu); + this.element.setAttribute("context", menu.id); + + this._contextMenu = menu; + }, + + /** + * Update the rule view's context menu by disabling irrelevant menuitems and + * enabling relevant ones. + * + * @param aEvent The event object + */ + _onMenuUpdate: function CssRuleView_onMenuUpdate(aEvent) + { + // Copy selection. + let disable = this.doc.defaultView.getSelection().isCollapsed; + this._copyItem.disabled = disable; + + // Copy property, copy property name & copy property value. + let node = this.doc.popupNode; + if (!node.classList.contains("ruleview-property") && + !node.classList.contains("ruleview-computed")) { + while (node = node.parentElement) { + if (node.classList.contains("ruleview-property") || + node.classList.contains("ruleview-computed")) { + break; + } + } + } + let disablePropertyItems = !node || (node && + !node.classList.contains("ruleview-property") && + !node.classList.contains("ruleview-computed")); + + this._declarationItem.disabled = disablePropertyItems; + this._propertyItem.disabled = disablePropertyItems; + this._propertyValueItem.disabled = disablePropertyItems; + + dump("Done updating menu!\n"); + }, + + _onMouseDown: function CssRuleView_onMouseDown() + { + this.element.addEventListener("mousemove", this._boundMouseMove); + }, + + _onMouseUp: function CssRuleView_onMouseUp() + { + this.element.removeEventListener("mousemove", this._boundMouseMove); + this._selectionMode = false; + }, + + _onMouseMove: function CssRuleView_onMouseMove() + { + this._selectionMode = true; + }, + + /** + * Copy selected text from the rule view. + * + * @param aEvent The event object + */ + _onCopy: function CssRuleView_onCopy(aEvent) + { + let win = this.doc.defaultView; + let text = win.getSelection().toString(); + + // Remove any double newlines. + text = text.replace(/(\r?\n)\r?\n/g, "$1"); + + // Remove "inline" + let inline = _strings.GetStringFromName("rule.sourceInline"); + let rx = new RegExp("^" + inline + "\\r?\\n?", "g"); + text = text.replace(rx, ""); + + // Remove file:line + text = text.replace(/[\w\.]+:\d+(\r?\n)/g, "$1"); + + // Remove inherited from: line + let inheritedFrom = _strings. + GetStringFromName("rule.inheritedSource"); + inheritedFrom = inheritedFrom.replace(/\s%S\s\(%S\)/g, ""); + rx = new RegExp("(\r?\n)" + inheritedFrom + ".*", "g"); + text = text.replace(rx, "$1"); + + clipboardHelper.copyString(text); + + if (aEvent) { + aEvent.preventDefault(); + } + }, + + /** + * Copy a rule from the rule view. + * + * @param aEvent The event object + */ + _onCopyRule: function CssRuleView_onCopyRule(aEvent) + { + let node = this.doc.popupNode; + if (node.className != "ruleview-code") { + if (node.className == "ruleview-rule-source") { + node = node.nextElementSibling; + } else { + while (node = node.parentElement) { + if (node.className == "ruleview-code") { + break; + } + } + } + } + + if (node.className == "ruleview-code") { + // We need to strip expanded properties from the node because we use + // node.textContent below, which also gets text from hidden nodes. The + // simplest way to do this is to clone the node and remove them from the + // clone. + node = node.cloneNode(); + let computed = node.querySelector(".ruleview-computedlist"); + if (computed) { + computed.parentNode.removeChild(computed); + } + } + + let text = node.textContent; + + // Format the rule + if (osString == "WINNT") { + text = text.replace(/{/g, "{\r\n "); + text = text.replace(/;/g, ";\r\n "); + text = text.replace(/\s*}/g, "\r\n}"); + } else { + text = text.replace(/{/g, "{\n "); + text = text.replace(/;/g, ";\n "); + text = text.replace(/\s*}/g, "\n}"); + } + + clipboardHelper.copyString(text); + }, + + /** + * Copy a declaration from the rule view. + * + * @param aEvent The event object + */ + _onCopyDeclaration: function CssRuleView_onCopyDeclaration(aEvent) + { + let node = this.doc.popupNode; + if (!node.classList.contains("ruleview-property") && + !node.classList.contains("ruleview-computed")) { + while (node = node.parentElement) { + if (node.classList.contains("ruleview-property") || + node.classList.contains("ruleview-computed")) { + break; + } + } + } + + // We need to strip expanded properties from the node because we use + // node.textContent below, which also gets text from hidden nodes. The + // simplest way to do this is to clone the node and remove them from the + // clone. + node = node.cloneNode(); + let computed = node.querySelector(".ruleview-computedlist"); + if (computed) { + computed.parentNode.removeChild(computed); + } + clipboardHelper.copyString(node.textContent); + }, + + /** + * Copy a property name from the rule view. + * + * @param aEvent The event object + */ + _onCopyProperty: function CssRuleView_onCopyProperty(aEvent) + { + let node = this.doc.popupNode; + + if (!node.classList.contains("ruleview-propertyname")) { + node = node.querySelector(".ruleview-propertyname"); + } + + if (node) { + clipboardHelper.copyString(node.textContent); + } + }, + + /** + * Copy a property value from the rule view. + * + * @param aEvent The event object + */ + _onCopyPropertyValue: function CssRuleView_onCopyPropertyValue(aEvent) + { + let node = this.doc.popupNode; + + if (!node.classList.contains("ruleview-propertyvalue")) { + node = node.querySelector(".ruleview-propertyvalue"); + } + + if (node) { + clipboardHelper.copyString(node.textContent); + } + } }; /** @@ -1569,6 +1869,18 @@ function createChild(aParent, aTag, aAttributes) return elt; } +function createMenuItem(aMenu, aAttributes) +{ + let item = aMenu.ownerDocument.createElementNS(XUL_NS, "menuitem"); + item.setAttribute("label", _strings.GetStringFromName(aAttributes.label)); + item.setAttribute("accesskey", _strings.GetStringFromName(aAttributes.accesskey)); + item.addEventListener("command", aAttributes.command); + + aMenu.appendChild(item); + + return item; +} + /** * Append a text node to an element. */ @@ -1598,3 +1910,18 @@ function moveFocus(aWin, aDirection) let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); fm.moveFocus(aWin, null, aDirection, 0); } + +XPCOMUtils.defineLazyGetter(this, "clipboardHelper", function() { + return Cc["@mozilla.org/widget/clipboardhelper;1"]. + getService(Ci.nsIClipboardHelper); +}); + +XPCOMUtils.defineLazyGetter(this, "_strings", function() { + return Services.strings.createBundle( + "chrome://browser/locale/devtools/styleinspector.properties"); +}); + +XPCOMUtils.defineLazyGetter(this, "osString", function() { + return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS; +}); + diff --git a/browser/devtools/styleinspector/test/browser_ruleview_bug_703643_context_menu_copy.js b/browser/devtools/styleinspector/test/browser_ruleview_bug_703643_context_menu_copy.js index 9dd38b895bb..7f3faaef624 100644 --- a/browser/devtools/styleinspector/test/browser_ruleview_bug_703643_context_menu_copy.js +++ b/browser/devtools/styleinspector/test/browser_ruleview_bug_703643_context_menu_copy.js @@ -70,7 +70,7 @@ function testClip() InspectorUI.INSPECTOR_NOTIFICATIONS.RULEVIEWREADY, false); executeSoon(function() { - info("Checking that InspectorUI.ruleViewCopyRule() returns " + + info("Checking that _onCopyRule() returns " + "the correct clipboard value"); let expectedPattern = "element {[\\r\\n]+" + " margin: 10em;[\\r\\n]+" + @@ -106,12 +106,12 @@ function checkCopyRule() { EventUtils.synthesizeMouse(prop, 1, 1, { type: "contextmenu", button: 2 }, ruleView.contentWindow); - InspectorUI.ruleViewCopyRule(); + InspectorUI.ruleView._boundCopyRule(); } function checkCopyProperty() { - info("Checking that InspectorUI.cssRuleViewBoundCopyDeclaration() returns " + + info("Checking that _onCopyDeclaration() returns " + "the correct clipboard value"); let expectedPattern = "font-family: helvetica,sans-serif;"; info("Expected pattern: " + expectedPattern); @@ -119,13 +119,13 @@ function checkCopyProperty() SimpleTest.waitForClipboard(function IUI_boundCopyPropCheck() { return checkClipboardData(expectedPattern); }, - InspectorUI.cssRuleViewBoundCopyDeclaration, + InspectorUI.ruleView._boundCopyDeclaration, checkCopyPropertyName, checkCopyPropertyName); } function checkCopyPropertyName() { - info("Checking that InspectorUI.cssRuleViewBoundCopyProperty() returns " + + info("Checking that _onCopyProperty() returns " + "the correct clipboard value"); let expectedPattern = "font-family"; info("Expected pattern: " + expectedPattern); @@ -133,13 +133,13 @@ function checkCopyPropertyName() SimpleTest.waitForClipboard(function IUI_boundCopyPropNameCheck() { return checkClipboardData(expectedPattern); }, - InspectorUI.cssRuleViewBoundCopyProperty, + InspectorUI.ruleView._boundCopyProperty, checkCopyPropertyValue, checkCopyPropertyValue); } function checkCopyPropertyValue() { - info("Checking that InspectorUI.cssRuleViewBoundCopyPropertyValue() " + + info("Checking that _onCopyPropertyValue() " + " returns the correct clipboard value"); let expectedPattern = "helvetica,sans-serif"; info("Expected pattern: " + expectedPattern); @@ -147,7 +147,7 @@ function checkCopyPropertyValue() SimpleTest.waitForClipboard(function IUI_boundCopyPropValueCheck() { return checkClipboardData(expectedPattern); }, - InspectorUI.cssRuleViewBoundCopyPropertyValue, + InspectorUI.ruleView._boundCopyPropertyValue, checkCopySelection, checkCopySelection); } @@ -162,7 +162,7 @@ function checkCopySelection() range.setEnd(props[4], 8); ruleView.contentWindow.getSelection().addRange(range); - info("Checking that InspectorUI.cssRuleViewBoundCopy() returns the correct" + + info("Checking that _onCopy() returns the correct" + "clipboard value"); let expectedPattern = " margin: 10em;[\\r\\n]+" + " font-size: 14pt;[\\r\\n]+" + @@ -175,7 +175,7 @@ function checkCopySelection() SimpleTest.waitForClipboard(function IUI_boundCopyCheck() { return checkClipboardData(expectedPattern); - },InspectorUI.cssRuleViewBoundCopy, finishup, finishup); + },InspectorUI.ruleView._boundCopy, finishup, finishup); } function checkClipboardData(aExpectedPattern)