Bug 1290086 - use multiline inplace editor for markupview autocompletes;r=gl
MozReview-Commit-ID: AcWBWdq5q7Q
--- a/devtools/client/inspector/markup/markup.js
+++ b/devtools/client/inspector/markup/markup.js
@@ -2902,21 +2902,17 @@ function TextEditor(container, node, tem
this.markup.template(templateId, this);
editableField({
element: this.value,
stopOnReturn: true,
trigger: "dblclick",
multiline: true,
- maxWidth: () => {
- let elementRect = this.value.getBoundingClientRect();
- let containerRect = this.container.elt.getBoundingClientRect();
- return containerRect.right - elementRect.left - 2;
- },
+ maxWidth: () => getAutocompleteMaxWidth(this.value, this.container.elt),
trimOutput: false,
done: (val, commit) => {
if (!commit) {
return;
}
this.node.getNodeValue().then(longstr => {
longstr.string().then(oldValue => {
longstr.release().then(null, console.error);
@@ -3001,26 +2997,30 @@ function ElementEditor(container, node)
// Make the tag name editable (unless this is a remote node or
// a document element)
if (!node.isDocumentElement) {
// Make the tag optionally tabbable but not by default.
this.tag.setAttribute("tabindex", "-1");
editableField({
element: this.tag,
+ multiline: true,
+ maxWidth: () => getAutocompleteMaxWidth(this.tag, this.container.elt),
trigger: "dblclick",
stopOnReturn: true,
done: this.onTagEdit.bind(this),
cssProperties: this._cssProperties
});
}
// Make the new attribute space editable.
this.newAttr.editMode = editableField({
element: this.newAttr,
+ multiline: true,
+ maxWidth: () => getAutocompleteMaxWidth(this.newAttr, this.container.elt),
trigger: "dblclick",
stopOnReturn: true,
contentType: InplaceEditor.CONTENT_TYPES.CSS_MIXED,
popup: this.markup.popup,
done: (val, commit) => {
if (!commit) {
return;
}
@@ -3231,16 +3231,18 @@ ElementEditor.prototype = {
// Make the attribute editable.
attr.editMode = editableField({
element: inner,
trigger: "dblclick",
stopOnReturn: true,
selectAll: false,
initial: initial,
+ multiline: true,
+ maxWidth: () => getAutocompleteMaxWidth(inner, this.container.elt),
contentType: InplaceEditor.CONTENT_TYPES.CSS_MIXED,
popup: this.markup.popup,
start: (editor, event) => {
// If the editing was started inside the name or value areas,
// select accordingly.
if (event && event.target === name) {
editor.input.setSelectionRange(0, name.textContent.length);
} else if (event && event.target.closest(".attr-value") === val) {
@@ -3603,16 +3605,27 @@ function flashElementOff(backgroundElt,
function map(value, oldMin, oldMax, newMin, newMax) {
let ratio = oldMax - oldMin;
if (ratio == 0) {
return value;
}
return newMin + (newMax - newMin) * ((value - oldMin) / ratio);
}
+/**
+ * Retrieve the available width between a provided element left edge and a container right
+ * edge. This used can be used as a max-width for inplace-editor (autocomplete) widgets
+ * replacing Editor elements of the the markup-view;
+ */
+function getAutocompleteMaxWidth(element, container) {
+ let elementRect = element.getBoundingClientRect();
+ let containerRect = container.getBoundingClientRect();
+ return containerRect.right - elementRect.left - 2;
+}
+
loader.lazyGetter(MarkupView.prototype, "strings", () => Services.strings.createBundle(
"chrome://devtools/locale/inspector.properties"
));
XPCOMUtils.defineLazyGetter(this, "clipboardHelper", function () {
return Cc["@mozilla.org/widget/clipboardhelper;1"]
.getService(Ci.nsIClipboardHelper);
});
--- a/devtools/client/inspector/markup/test/browser.ini
+++ b/devtools/client/inspector/markup/test/browser.ini
@@ -136,16 +136,17 @@ skip-if = e10s # Bug 1036409 - The last
[browser_markup_tag_edit_06.js]
[browser_markup_tag_edit_07.js]
[browser_markup_tag_edit_08.js]
[browser_markup_tag_edit_09.js]
[browser_markup_tag_edit_10.js]
[browser_markup_tag_edit_11.js]
[browser_markup_tag_edit_12.js]
[browser_markup_tag_edit_13-other.js]
+[browser_markup_tag_edit_long-classname.js]
[browser_markup_textcontent_display.js]
[browser_markup_textcontent_edit_01.js]
[browser_markup_textcontent_edit_02.js]
[browser_markup_toggle_01.js]
[browser_markup_toggle_02.js]
[browser_markup_toggle_03.js]
[browser_markup_update-on-navigtion.js]
[browser_markup_void_elements_html.js]
--- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_12.js
+++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_12.js
@@ -64,17 +64,17 @@ function* testAttributeDeletion(inspecto
info("Deleting the last attribute");
yield editAttributeAndTab(" ", inspector);
// Check we're on the newattr element
let focusedAttr = Services.focus.focusedElement;
ok(focusedAttr.classList.contains("styleinspector-propertyeditor"),
"in newattr");
- is(focusedAttr.tagName, "input", "newattr is active");
+ is(focusedAttr.tagName, "textarea", "newattr is active");
}
function* editAttributeAndTab(newValue, inspector, goPrevious) {
let onEditMutation = inspector.markup.once("refocusedonedit");
inspector.markup.doc.activeElement.value = newValue;
if (goPrevious) {
EventUtils.synthesizeKey("VK_TAB", { shiftKey: true },
inspector.panelWin);
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_long-classname.js
@@ -0,0 +1,42 @@
+/* vim: set 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 that editing long classnames shows the whole class attribute without scrollbars.
+
+const classname = "this-long-class-attribute-should-be-displayed " +
+ "without-overflow-when-switching-to-edit-mode " +
+ "AAAAAAAAAAAA-BBBBBBBBBBBBB-CCCCCCCCCCCCC-DDDDDDDDDDDDDD-EEEEEEEEEEEEE";
+const TEST_URL = `data:text/html;charset=utf8, <div class="${classname}"></div>`;
+
+add_task(function* () {
+ let {inspector} = yield openInspectorForURL(TEST_URL);
+
+ info("Select node and make sure it is focused");
+ yield selectNode("div", inspector);
+ yield clickContainer("div", inspector);
+
+ let container = yield focusNode("div", inspector);
+ ok(container && container.editor, "The markup-container was found");
+
+ info("Listening for the markupmutation event");
+ let nodeMutated = inspector.once("markupmutation");
+ let attr = container.editor.attrElements.get("class").querySelector(".editable");
+
+ attr.focus();
+ EventUtils.sendKey("return", inspector.panelWin);
+ let input = inplaceEditor(attr).input;
+ ok(input, "Found editable field for class attribute");
+
+ is(input.scrollHeight, input.clientHeight, "input should not have vertical scrollbars");
+ is(input.scrollWidth, input.clientWidth, "input should not have horizontal scrollbars");
+ input.value = "class=\"other value\"";
+
+ info("Commit the new class value");
+ EventUtils.sendKey("return", inspector.panelWin);
+
+ info("Wait for the markup-mutation event");
+ yield nodeMutated;
+});
--- a/devtools/client/inspector/markup/test/head.js
+++ b/devtools/client/inspector/markup/test/head.js
@@ -384,23 +384,26 @@ function collapseSelectionAndShiftTab(in
/**
* Check that the current focused element is an attribute element in the markup
* view.
* @param {String} attrName The attribute name expected to be found
* @param {Boolean} editMode Whether or not the attribute should be in edit mode
*/
function checkFocusedAttribute(attrName, editMode) {
let focusedAttr = Services.focus.focusedElement;
- is(focusedAttr ? focusedAttr.parentNode.dataset.attr : undefined,
- attrName, attrName + " attribute editor is currently focused.");
- is(focusedAttr ? focusedAttr.tagName : undefined,
- editMode ? "input" : "span",
- editMode
- ? attrName + " is in edit mode"
- : attrName + " is not in edit mode");
+ ok(focusedAttr, "Has a focused element");
+
+ let dataAttr = focusedAttr.parentNode.dataset.attr;
+ is(dataAttr, attrName, attrName + " attribute editor is currently focused.");
+ if (editMode) {
+ // Using a multiline editor for attributes, the focused element should be a textarea.
+ is(focusedAttr.tagName, "textarea", attrName + "is in edit mode");
+ } else {
+ is(focusedAttr.tagName, "span", attrName + "is not in edit mode");
+ }
}
/**
* Get attributes for node as how they are represented in editor.
*
* @param {String} selector
* @param {InspectorPanel} inspector
* @return {Promise}