From 901c1e8bf4197cc2554f44c747eb298c57307384 Mon Sep 17 00:00:00 2001 From: Michael Ratcliffe Date: Wed, 31 Oct 2012 18:25:08 +0200 Subject: [PATCH] Bug 788458 - Fix issues with copy / paste in rule and computed views; r=dcamp --- .../devtools/styleinspector/CssRuleView.jsm | 52 ++++++-- ...r_ruleview_bug_703643_context_menu_copy.js | 113 +++++++++--------- 2 files changed, 96 insertions(+), 69 deletions(-) diff --git a/browser/devtools/styleinspector/CssRuleView.jsm b/browser/devtools/styleinspector/CssRuleView.jsm index df0a9139bb3..57db3152516 100644 --- a/browser/devtools/styleinspector/CssRuleView.jsm +++ b/browser/devtools/styleinspector/CssRuleView.jsm @@ -1124,12 +1124,16 @@ CssRuleView.prototype = { */ _onMenuUpdate: function CssRuleView_onMenuUpdate(aEvent) { + let node = this.doc.popupNode; + // Copy selection. - let disable = this.doc.defaultView.getSelection().isCollapsed; + let editorSelection = node.className == "styleinspector-propertyeditor" && + node.selectionEnd - node.selectionStart != 0; + let disable = this.doc.defaultView.getSelection().isCollapsed && + !editorSelection; this._copyItem.disabled = disable; // Copy property, copy property name & copy property value. - let node = this.doc.popupNode; if (!node) { return; } @@ -1159,16 +1163,26 @@ CssRuleView.prototype = { */ _onCopy: function CssRuleView_onCopy(aEvent) { - let win = this.doc.defaultView; - let text = win.getSelection().toString(); + let target = this.doc.popupNode || aEvent.target; + let text; - // Remove any double newlines. - text = text.replace(/(\r?\n)\r?\n/g, "$1"); + if (target.nodeName == "input") { + let start = Math.min(target.selectionStart, target.selectionEnd); + let end = Math.max(target.selectionStart, target.selectionEnd); + let count = end - start; + text = target.value.substr(start, count); + } else { + let win = this.doc.defaultView; + text = win.getSelection().toString(); - // Remove "inline" - let inline = _strings.GetStringFromName("rule.sourceInline"); - let rx = new RegExp("^" + inline + "\\r?\\n?", "g"); - text = text.replace(rx, ""); + // 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, ""); + } clipboardHelper.copyString(text, this.doc); @@ -1277,12 +1291,13 @@ CssRuleView.prototype = { _onCopyProperty: function CssRuleView_onCopyProperty(aEvent) { let node = this.doc.popupNode; + if (!node) { return; } if (!node.classList.contains("ruleview-propertyname")) { - node = node.querySelector(".ruleview-propertyname"); + node = node.parentNode.parentNode.querySelector(".ruleview-propertyname"); } if (node) { @@ -1303,7 +1318,7 @@ CssRuleView.prototype = { } if (!node.classList.contains("ruleview-propertyvalue")) { - node = node.querySelector(".ruleview-propertyvalue"); + node = node.parentNode.parentNode.querySelector(".ruleview-propertyvalue"); } if (node) { @@ -1381,6 +1396,19 @@ RuleEditor.prototype = { } }.bind(this), false); + this.element.addEventListener("mousedown", function() { + let editorNodes = + this.doc.querySelectorAll(".styleinspector-propertyeditor"); + + if (editorNodes) { + for (let node of editorNodes) { + if (node.inplaceEditor) { + node.inplaceEditor._clear(); + } + } + } + }.bind(this), false); + this.propertyList = createChild(code, "ul", { class: "ruleview-propertylist" }); 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 e23ad04be35..0183314d1db 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 @@ -88,8 +88,8 @@ function testClip() SimpleTest.waitForClipboard(function IUI_boundCopyPropCheck() { return checkClipboardData(expectedPattern); }, - checkCopyRule, checkCopyRuleWithEditorSelected, function() { - failedClipboard(expectedPattern, checkCopyRuleWithEditorSelected); + checkCopyRule, checkCopyProperty, function() { + failedClipboard(expectedPattern, checkCopyProperty); }); }); } @@ -118,57 +118,6 @@ function checkCopyRule() { menu.hidePopup(); } -function checkCopyRuleWithEditorSelected() -{ - let contentDoc = ruleViewFrame().contentDocument; - let rules = contentDoc.querySelectorAll(".ruleview-rule"); - let propNodes = contentDoc.querySelectorAll(".ruleview-property"); - let propNode = propNodes[2]; - let propNameNode = propNode.querySelector(".ruleview-propertyname"); - - ok(propNameNode, "we have the property name node"); - - info("Checking that _boundCopyRule() returns the correct clipboard value"); - let expectedPattern = "element {[\\r\\n]+" + - " margin: 10em;[\\r\\n]+" + - " font-size: 14pt;[\\r\\n]+" + - " font-family: helvetica,sans-serif;[\\r\\n]+" + - " color: rgb\\(170, 170, 170\\);[\\r\\n]+" + - "}[\\r\\n]*"; - - let elementRuleEditor = rules[0]._ruleEditor; - waitForEditorFocus(elementRuleEditor.element, function onNewElement(aEditor) { - ok(aEditor, "we have the editor"); - - waitForBlur.editor = aEditor; - - // We need the context menu to open in the correct place in order for - // popupNode to be propertly set. - EventUtils.synthesizeMouse(aEditor.input, 1, 1, - { type: "contextmenu", button: 2 }, ruleViewFrame().contentWindow); - - SimpleTest.waitForClipboard(function IUI_boundCopyCheckWithSelection() { - let menu = contentDoc.querySelector("#rule-view-context-menu"); - ok(menu, "we have the context menu"); - menu.hidePopup(); - - return checkClipboardData(expectedPattern); - }, ruleView()._boundCopyRule, waitForBlur, function() { - failedClipboard(expectedPattern, checkCopyProperty); - }); - }); - EventUtils.synthesizeMouse(propNameNode, 1, 1, { }, ruleViewFrame().contentWindow); -} - -function waitForBlur() -{ - waitForEditorBlur(waitForBlur.editor, function() { - waitForBlur.editor = null; - checkCopyProperty(); - }); - waitForBlur.editor.input.blur(); -} - function checkCopyProperty() { let contentDoc = ruleViewFrame().contentDocument; @@ -197,7 +146,7 @@ function checkCopyPropertyName() { info("Checking that _onCopyProperty() returns " + "the correct clipboard value"); - let expectedPattern = "font-family"; + let expectedPattern = "margin"; SimpleTest.waitForClipboard(function IUI_boundCopyPropNameCheck() { return checkClipboardData(expectedPattern); @@ -212,7 +161,7 @@ function checkCopyPropertyValue() { info("Checking that _onCopyPropertyValue() " + " returns the correct clipboard value"); - let expectedPattern = "helvetica,sans-serif"; + let expectedPattern = "10em"; SimpleTest.waitForClipboard(function IUI_boundCopyPropValueCheck() { return checkClipboardData(expectedPattern); @@ -248,11 +197,61 @@ function checkCopySelection() SimpleTest.waitForClipboard(function IUI_boundCopyCheck() { return checkClipboardData(expectedPattern); - },ruleView()._boundCopy, finishup, function() { - failedClipboard(expectedPattern, finishup); + },ruleView()._boundCopy, testSimpleCopy, function() { + failedClipboard(expectedPattern, testSimpleCopy); }); } +function testSimpleCopy() +{ + executeSoon(function() { + info("Checking that _onCopy() returns the correct clipboard value"); + let expectedPattern = "element {[\\r\\n]+" + + " margin: 10em;[\\r\\n]+" + + " font-size: 14pt;[\\r\\n]+" + + " font-family: helvetica,sans-serif;[\\r\\n]+" + + " color: rgb\\(170, 170, 170\\);[\\r\\n]+" + + "}[\\r\\n]*"; + + SimpleTest.waitForClipboard(function IUI_testSimpleCopy() { + return checkClipboardData(expectedPattern); + }, + checkSimpleCopy, finishup, function() { + failedClipboard(expectedPattern, finishup); + }); + }); +} + +function checkSimpleCopy() { + let contentDoc = ruleViewFrame().contentDocument; + let props = contentDoc.querySelectorAll(".ruleview-code"); + + is(props.length, 2, "checking property length"); + + let prop = props[0]; + + selectNode(prop); + + // We need the context menu to open in the correct place in order for + // popupNode to be propertly set. + EventUtils.synthesizeMouse(prop, 1, 1, { type: "contextmenu", button: 2 }, + ruleViewFrame().contentWindow); + + ruleView()._boundCopy(); + let menu = contentDoc.querySelector("#rule-view-context-menu"); + ok(menu, "we have the context menu"); + menu.hidePopup(); +} + +function selectNode(aNode) { + let doc = aNode.ownerDocument; + let win = doc.defaultView; + let range = doc.createRange(); + + range.selectNode(aNode); + win.getSelection().addRange(range); +} + function checkClipboardData(aExpectedPattern) { let actual = SpecialPowers.getClipboardData("text/unicode");