Bug 1310310 - ruleview stylesheet link using span instead of label;r=jsnajdr draft
authorJulian Descottes <jdescottes@mozilla.com>
Sun, 16 Oct 2016 10:55:24 +0200
changeset 426053 aebbe671eb788c3876c0f3be9dd01b4c297c3c54
parent 425967 94b0fddf96b43942bdd851a3275042909ea37e09
child 534083 053f455ad8a71b019e9c0044ade7e444e3e9c507
push id32606
push userjdescottes@mozilla.com
push dateMon, 17 Oct 2016 18:15:24 +0000
reviewersjsnajdr
bugs1310310
milestone52.0a1
Bug 1310310 - ruleview stylesheet link using span instead of label;r=jsnajdr MozReview-Commit-ID: Fl6vKp2GbKV
devtools/client/inspector/rules/test/browser_rules_invalid-source-map.js
devtools/client/inspector/rules/test/browser_rules_original-source-link.js
devtools/client/inspector/rules/test/browser_rules_style-editor-link.js
devtools/client/inspector/rules/test/head.js
devtools/client/inspector/rules/views/rule-editor.js
devtools/client/inspector/shared/test/head.js
devtools/client/themes/rules.css
--- a/devtools/client/inspector/rules/test/browser_rules_invalid-source-map.js
+++ b/devtools/client/inspector/rules/test/browser_rules_invalid-source-map.js
@@ -30,14 +30,15 @@ add_task(function* () {
 
   yield verifyLinkText(view, CSS_LOC);
 
   Services.prefs.clearUserPref(PREF);
 });
 
 function verifyLinkText(view, text) {
   info("Verifying that the rule-view stylesheet link is " + text);
-  let label = getRuleViewLinkByIndex(view, 1).querySelector("label");
+  let label = getRuleViewLinkByIndex(view, 1)
+    .querySelector(".ruleview-rule-source-label");
   return waitForSuccess(
-    () => label.getAttribute("value") == text,
+    () => label.textContent == text,
     "Link text changed to display correct location: " + text
   );
 }
--- a/devtools/client/inspector/rules/test/browser_rules_original-source-link.js
+++ b/devtools/client/inspector/rules/test/browser_rules_original-source-link.js
@@ -72,13 +72,14 @@ function editorSelected(editor) {
     "selected stylesheet is correct one");
 
   let {line} = editor.sourceEditor.getCursor();
   is(line, 3, "cursor is at correct line number in original source");
 }
 
 function verifyLinkText(text, view) {
   info("Verifying that the rule-view stylesheet link is " + text);
-  let label = getRuleViewLinkByIndex(view, 1).querySelector("label");
+  let label = getRuleViewLinkByIndex(view, 1)
+    .querySelector(".ruleview-rule-source-label");
   return waitForSuccess(function* () {
-    return label.getAttribute("value") == text;
+    return label.textContent == text;
   }, "Link text changed to display correct location: " + text);
 }
--- a/devtools/client/inspector/rules/test/browser_rules_style-editor-link.js
+++ b/devtools/client/inspector/rules/test/browser_rules_style-editor-link.js
@@ -175,18 +175,18 @@ function* testDisabledStyleEditor(view, 
   is(toolbox.currentToolId, "styleeditor", "Style Editor should be selected");
 
   Services.prefs.clearUserPref("devtools.styleeditor.enabled");
 }
 
 function testRuleViewLinkLabel(view) {
   let link = getRuleViewLinkByIndex(view, 2);
   let labelElem = link.querySelector(".ruleview-rule-source-label");
-  let value = labelElem.getAttribute("value");
-  let tooltipText = labelElem.getAttribute("tooltiptext");
+  let value = labelElem.textContent;
+  let tooltipText = labelElem.getAttribute("title");
 
   is(value, EXTERNAL_STYLESHEET_FILE_NAME + ":1",
     "rule view stylesheet display value matches filename and line number");
   is(tooltipText, EXTERNAL_STYLESHEET_URL + ":1",
     "rule view stylesheet tooltip text matches the full URI path");
 }
 
 function testUnselectableRuleViewLink(view, index) {
--- a/devtools/client/inspector/rules/test/head.js
+++ b/devtools/client/inspector/rules/test/head.js
@@ -471,17 +471,17 @@ function getRuleViewLinkByIndex(view, in
  * @param {CssRuleView} view
  *        The instance of the rule-view panel
  * @param {Number} index
  *        The index of the link to get
  * @return {String} The string at this index
  */
 function getRuleViewLinkTextByIndex(view, index) {
   let link = getRuleViewLinkByIndex(view, index);
-  return link.querySelector(".ruleview-rule-source-label").value;
+  return link.querySelector(".ruleview-rule-source-label").textContent;
 }
 
 /**
  * Simulate adding a new property in an existing rule in the rule-view.
  *
  * @param {CssRuleView} view
  *        The instance of the rule-view panel
  * @param {Number} ruleIndex
--- a/devtools/client/inspector/rules/views/rule-editor.js
+++ b/devtools/client/inspector/rules/views/rule-editor.js
@@ -28,19 +28,16 @@ const promise = require("promise");
 const Services = require("Services");
 const EventEmitter = require("devtools/shared/event-emitter");
 const {Task} = require("devtools/shared/task");
 
 const STYLE_INSPECTOR_PROPERTIES = "devtools-shared/locale/styleinspector.properties";
 const {LocalizationHelper} = require("devtools/shared/l10n");
 const STYLE_INSPECTOR_L10N = new LocalizationHelper(STYLE_INSPECTOR_PROPERTIES);
 
-const HTML_NS = "http://www.w3.org/1999/xhtml";
-const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-
 /**
  * RuleEditor is responsible for the following:
  *   Owns a Rule object and creates a list of TextPropertyEditors
  *     for its TextProperties.
  *   Manages creation of new text properties.
  *
  * One step of a RuleEditor's instantiation is figuring out what's the original
  * source link to the parent stylesheet (in case of source maps). This step is
@@ -93,17 +90,17 @@ RuleEditor.prototype = {
       this.rule.domRule.type !== CSSRule.KEYFRAME_RULE;
 
     // Do not allow editing anonymousselectors until we can
     // detect mutations on  pseudo elements in Bug 1034110.
     return trait && !this.rule.elementStyle.element.isAnonymous;
   },
 
   _create: function () {
-    this.element = this.doc.createElementNS(HTML_NS, "div");
+    this.element = this.doc.createElement("div");
     this.element.className = "ruleview-rule theme-separator";
     this.element.setAttribute("uneditable", !this.isEditable);
     this.element.setAttribute("unmatched", this.rule.isUnmatched);
     this.element._ruleEditor = this;
 
     // Give a relative position for the inplace editor's measurement
     // span to be placed absolutely against.
     this.element.style.position = "relative";
@@ -114,18 +111,17 @@ RuleEditor.prototype = {
     });
     this.source.addEventListener("click", function () {
       if (this.source.hasAttribute("unselectable")) {
         return;
       }
       let rule = this.rule.domRule;
       this.ruleView.emit("ruleview-linked-clicked", rule);
     }.bind(this));
-    let sourceLabel = this.doc.createElementNS(XUL_NS, "label");
-    sourceLabel.setAttribute("crop", "center");
+    let sourceLabel = this.doc.createElement("span");
     sourceLabel.classList.add("ruleview-rule-source-label");
     this.source.appendChild(sourceLabel);
 
     this.updateSourceLink();
 
     let code = createChild(this.element, "div", {
       class: "ruleview-code"
     });
@@ -224,51 +220,51 @@ RuleEditor.prototype = {
 
   updateSourceLink: function () {
     let sourceLabel = this.element.querySelector(".ruleview-rule-source-label");
     let title = this.rule.title;
     let sourceHref = (this.rule.sheet && this.rule.sheet.href) ?
       this.rule.sheet.href : title;
     let sourceLine = this.rule.ruleLine > 0 ? ":" + this.rule.ruleLine : "";
 
-    sourceLabel.setAttribute("tooltiptext", sourceHref + sourceLine);
+    sourceLabel.setAttribute("title", sourceHref + sourceLine);
 
     if (this.toolbox.isToolRegistered("styleeditor")) {
       this.source.removeAttribute("unselectable");
     } else {
       this.source.setAttribute("unselectable", true);
     }
 
     if (this.rule.isSystem) {
       let uaLabel = STYLE_INSPECTOR_L10N.getStr("rule.userAgentStyles");
-      sourceLabel.setAttribute("value", uaLabel + " " + title);
+      sourceLabel.textContent = uaLabel + " " + title;
 
       // Special case about:PreferenceStyleSheet, as it is generated on the
       // fly and the URI is not registered with the about: handler.
       // https://bugzilla.mozilla.org/show_bug.cgi?id=935803#c37
       if (sourceHref === "about:PreferenceStyleSheet") {
         this.source.setAttribute("unselectable", "true");
-        sourceLabel.setAttribute("value", uaLabel);
-        sourceLabel.removeAttribute("tooltiptext");
+        sourceLabel.textContent = uaLabel;
+        sourceLabel.removeAttribute("title");
       }
     } else {
-      sourceLabel.setAttribute("value", title);
+      sourceLabel.textContent = title;
       if (this.rule.ruleLine === -1 && this.rule.domRule.parentStyleSheet) {
         this.source.setAttribute("unselectable", "true");
       }
     }
 
     let showOrig = Services.prefs.getBoolPref(PREF_ORIG_SOURCES);
     if (showOrig && !this.rule.isSystem &&
         this.rule.domRule.type !== ELEMENT_STYLE) {
       // Only get the original source link if the right pref is set, if the rule
       // isn't a system rule and if it isn't an inline rule.
       this.rule.getOriginalSourceStrings().then((strings) => {
-        sourceLabel.setAttribute("value", strings.short);
-        sourceLabel.setAttribute("tooltiptext", strings.full);
+        sourceLabel.textContent = strings.short;
+        sourceLabel.setAttribute("title", strings.full);
       }, e => console.error(e)).then(() => {
         this.emit("source-link-updated");
       });
     } else {
       // If we're not getting the original source link, then we can emit the
       // event immediately (but still asynchronously to give consumers a chance
       // to register it after having instantiated the RuleEditor).
       promise.resolve().then(() => {
--- a/devtools/client/inspector/shared/test/head.js
+++ b/devtools/client/inspector/shared/test/head.js
@@ -415,17 +415,17 @@ function getRuleViewLinkByIndex(view, in
  * @param {CssRuleView} view
  *        The instance of the rule-view panel
  * @param {Number} index
  *        The index of the link to get
  * @return {String} The string at this index
  */
 function getRuleViewLinkTextByIndex(view, index) {
   let link = getRuleViewLinkByIndex(view, index);
-  return link.querySelector(".ruleview-rule-source-label").value;
+  return link.querySelector(".ruleview-rule-source-label").textContent;
 }
 
 /**
  * Click on a rule-view's close brace to focus a new property name editor
  *
  * @param {RuleEditor} ruleEditor
  *        An instance of RuleEditor that will receive the new property
  * @return a promise that resolves to the newly created editor when ready and
--- a/devtools/client/themes/rules.css
+++ b/devtools/client/themes/rules.css
@@ -136,31 +136,44 @@
 .ruleview-computedlist[user-open],
 .ruleview-computedlist[filter-open] {
   display: block;
 }
 
 .ruleview-rule-source {
   text-align: end;
   float: right;
+  max-width: 100%;
+
+  /* Force RTL direction to crop the source link at the beginning. */
+  direction: rtl;
+  overflow: hidden;
+  text-overflow: ellipsis;
+
   -moz-user-select: none;
   margin-bottom: 2px;
 }
 
-.ruleview-rule-source > label {
+.ruleview-rule-source-label {
+  white-space: nowrap;
+  margin: 0;
   cursor: pointer;
-  margin: 0;
+
+  /* Create an LTR embed to avoid special characters being shifted to the start due to the
+     parent node direction: rtl; */
+  direction: ltr;
+  unicode-bidi: embed
 }
 
 .ruleview-rule-source[unselectable],
-.ruleview-rule-source[unselectable] > label {
+.ruleview-rule-source[unselectable] > .ruleview-rule-source-label {
   cursor: default;
 }
 
-.theme-firebug .ruleview-rule-source label {
+.theme-firebug .ruleview-rule-source-label {
   font-family: var(--proportional-font-family);
   font-weight: bold;
   color: #0000FF;
 }
 
 .ruleview-rule-source:not([unselectable]):hover {
   text-decoration: underline;
 }