Bug 702577 - Show font-family tooltip r=mratcliffe
authorMichael Ratcliffe <mratcliffe@mozilla.com>
Mon, 10 Mar 2014 13:24:58 +0000
changeset 190000 77bc8b1e43e7de4cb3668287802a71fca98c18a2
parent 189999 086c209d637f6d19d30ee3ff5f75613db99fde47
child 190001 a18c5fa023cb3ebc268ad7746c5bc093fab07149
push id3503
push userraliiev@mozilla.com
push dateMon, 28 Apr 2014 18:51:11 +0000
treeherdermozilla-beta@c95ac01e332e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmratcliffe
bugs702577
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 702577 - Show font-family tooltip r=mratcliffe
browser/devtools/shared/widgets/Tooltip.js
browser/devtools/styleinspector/computed-view.js
browser/devtools/styleinspector/rule-view.js
browser/devtools/styleinspector/test/browser.ini
browser/devtools/styleinspector/test/browser_bug702577_fontfamily_tooltip_longhand.js
browser/devtools/styleinspector/test/browser_bug702577_fontfamily_tooltip_shorthand.js
browser/themes/shared/devtools/common.css
browser/themes/shared/devtools/dark-theme.css
browser/themes/shared/devtools/light-theme.css
--- a/browser/devtools/shared/widgets/Tooltip.js
+++ b/browser/devtools/shared/widgets/Tooltip.js
@@ -741,16 +741,50 @@ Tooltip.prototype = {
           def.resolve();
         }
       });
     } else {
       def.reject();
     }
 
     return def.promise;
+  },
+
+  /**
+   * Set the content of the tooltip to display a font family preview.
+   * This is based on Lea Verou's Dablet. See https://github.com/LeaVerou/dabblet
+   * for more info.
+   *
+   * @param {String} font
+   *        The font family value.
+   */
+  setFontFamilyContent: function(font) {
+    let def = promise.defer();
+
+    if (font) {
+      // Main container
+      let vbox = this.doc.createElement("vbox");
+      vbox.setAttribute("flex", "1");
+
+      // Display the font family previewer
+      let previewer = this.doc.createElement("description");
+      previewer.setAttribute("flex", "1");
+      previewer.style.fontFamily = font;
+      previewer.classList.add("devtools-tooltip-font-previewer-text");
+      previewer.textContent = "(ABCabc123&@%)";
+      vbox.appendChild(previewer);
+
+      this.content = vbox;
+
+      def.resolve();
+    } else {
+      def.reject();
+    }
+
+    return def.promise;
   }
 };
 
 /**
  * Base class for all (color, gradient, ...)-swatch based value editors inside
  * tooltips
  *
  * @param {XULDocument} doc
--- a/browser/devtools/styleinspector/computed-view.js
+++ b/browser/devtools/styleinspector/computed-view.js
@@ -526,24 +526,30 @@ CssHtmlTree.prototype = {
       let propName = propValue.parentNode.querySelector(".property-name");
       if (propName.textContent === "background-image") {
         let maxDim = Services.prefs.getIntPref("devtools.inspector.imagePreviewTooltipSize");
         let uri = CssLogic.getBackgroundImageUriFromProperty(propValue.textContent);
         return this.tooltip.setRelativeImageContent(uri, inspector.inspector, maxDim);
       }
     }
 
-    // Test for css transform
     if (target.classList.contains("property-value")) {
       let propValue = target;
       let propName = target.parentNode.querySelector(".property-name");
+
+      // Test for css transform
       if (propName.textContent === "transform") {
         return this.tooltip.setCssTransformContent(propValue.textContent,
           this.pageStyle, this.viewedElement);
       }
+
+      // Test for font family
+      if (propName.textContent === "font-family") {
+        return this.tooltip.setFontFamilyContent(propValue.textContent);
+      }
     }
 
     // If the target isn't one that should receive a tooltip, signal it by rejecting
     // a promise
     return promise.reject();
   },
 
   /**
--- a/browser/devtools/styleinspector/rule-view.js
+++ b/browser/devtools/styleinspector/rule-view.js
@@ -1137,16 +1137,37 @@ CssRuleView.prototype = {
         let uri = CssLogic.getBackgroundImageUriFromProperty(property.value,
           property.rule.domRule.href);
         this.previewTooltip.setRelativeImageContent(uri,
           this.inspector.inspector, maxDim).then(def.resolve);
         hasTooltip = true;
       }
     }
 
+    // Get the nodes containing the property name and property value,
+    // and test for font family
+    let propertyRoot = target.parentNode;
+    let propertyNameNode = propertyRoot.querySelector(".ruleview-propertyname");
+
+    if (!propertyNameNode) {
+      propertyRoot = propertyRoot.parentNode;
+      propertyNameNode = propertyRoot.querySelector(".ruleview-propertyname");
+    }
+
+    let propertyName;
+    if (propertyNameNode) {
+      propertyName = propertyNameNode.textContent;
+    }
+
+    if (propertyName === "font-family" &&
+        target.classList.contains("ruleview-propertyvalue")) {
+      this.previewTooltip.setFontFamilyContent(target.textContent).then(def.resolve);
+      hasTooltip = true;
+    }
+
     if (hasTooltip) {
       this.colorPicker.revert();
       this.colorPicker.hide();
     } else {
       def.reject();
     }
 
     return def.promise;
--- a/browser/devtools/styleinspector/test/browser.ini
+++ b/browser/devtools/styleinspector/test/browser.ini
@@ -51,16 +51,18 @@ support-files =
 [browser_ruleview_bug_902966_revert_value_on_ESC.js]
 [browser_ruleview_pseudoelement.js]
 support-files = browser_ruleview_pseudoelement.html
 [browser_computedview_bug835808_keyboard_nav.js]
 [browser_bug913014_matched_expand.js]
 [browser_bug765105_background_image_tooltip.js]
 [browser_bug889638_rule_view_color_picker.js]
 [browser_bug726427_csstransform_tooltip.js]
+[browser_bug702577_fontfamily_tooltip_shorthand.js]
+[browser_bug702577_fontfamily_tooltip_longhand.js]
 [browser_bug940500_rule_view_pick_gradient_color.js]
 [browser_ruleview_original_source_link.js]
 support-files =
   sourcemaps.html
   sourcemaps.css
   sourcemaps.css.map
   sourcemaps.scss
 [browser_computedview_original_source_link.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_bug702577_fontfamily_tooltip_longhand.js
@@ -0,0 +1,131 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let contentDoc;
+let inspector;
+let ruleView;
+let computedView;
+
+const PAGE_CONTENT = [
+  '<style type="text/css">',
+  '  #testElement {',
+  '    font-family: cursive;',
+  '    color: #333;',
+  '    padding-left: 70px;',
+  '  }',
+  '</style>',
+  '<div id="testElement">test element</div>'
+].join("\n");
+
+function test() {
+  waitForExplicitFinish();
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
+    contentDoc = content.document;
+    waitForFocus(createDocument, content);
+  }, true);
+
+  content.location = "data:text/html;charset=utf-8,font family longhand tooltip test";
+}
+
+function createDocument() {
+  contentDoc.body.innerHTML = PAGE_CONTENT;
+
+  openRuleView((aInspector, aRuleView) => {
+    inspector = aInspector;
+    ruleView = aRuleView;
+    startTests();
+  });
+}
+
+function startTests() {
+  inspector.selection.setNode(contentDoc.querySelector("#testElement"));
+  inspector.once("inspector-updated", testRuleView);
+}
+
+function endTests() {
+  contentDoc = inspector = ruleView = computedView = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+function assertTooltipShownOn(tooltip, element, cb) {
+  // If there is indeed a show-on-hover on element, the xul panel will be shown
+  tooltip.panel.addEventListener("popupshown", function shown() {
+    tooltip.panel.removeEventListener("popupshown", shown, true);
+    cb();
+  }, true);
+  tooltip._showOnHover(element);
+}
+
+function testRuleView() {
+  info("Testing font-family tooltips in the rule view");
+
+  let panel = ruleView.previewTooltip.panel;
+
+  // Check that the rule view has a tooltip and that a XUL panel has been created
+  ok(ruleView.previewTooltip, "Tooltip instance exists");
+  ok(panel, "XUL panel exists");
+
+  // Get the font family property inside the rule view
+  let {valueSpan} = getRuleViewProperty("font-family");
+
+  // And verify that the tooltip gets shown on this property
+  assertTooltipShownOn(ruleView.previewTooltip, valueSpan, () => {
+    let description = panel.getElementsByTagName("description")[0];
+    is(description.style.fontFamily, "cursive", "Tooltips contains correct font-family style");
+
+    ruleView.previewTooltip.hide();
+
+    testComputedView();
+  });
+}
+
+function testComputedView() {
+  info("Testing font-family tooltips in the computed view");
+
+  inspector.sidebar.select("computedview");
+  computedView = inspector.sidebar.getWindowForTab("computedview").computedview.view;
+  let doc = computedView.styleDocument;
+
+  let panel = computedView.tooltip.panel;
+  let {valueSpan} = getComputedViewProperty("font-family");
+
+  assertTooltipShownOn(computedView.tooltip, valueSpan, () => {
+    let description = panel.getElementsByTagName("description")[0];
+    is(description.style.fontFamily, "cursive", "Tooltips contains correct font-family style");
+
+    computedView.tooltip.hide();
+
+    endTests();
+  });
+}
+
+function getRuleViewProperty(name) {
+  let prop = null;
+  [].forEach.call(ruleView.doc.querySelectorAll(".ruleview-property"), property => {
+    let nameSpan = property.querySelector(".ruleview-propertyname");
+    let valueSpan = property.querySelector(".ruleview-propertyvalue");
+
+    if (nameSpan.textContent === name) {
+      prop = {nameSpan: nameSpan, valueSpan: valueSpan};
+    }
+  });
+  return prop;
+}
+
+function getComputedViewProperty(name) {
+  let prop = null;
+  [].forEach.call(computedView.styleDocument.querySelectorAll(".property-view"), property => {
+    let nameSpan = property.querySelector(".property-name");
+    let valueSpan = property.querySelector(".property-value");
+
+    if (nameSpan.textContent === name) {
+      prop = {nameSpan: nameSpan, valueSpan: valueSpan};
+    }
+  });
+  return prop;
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_bug702577_fontfamily_tooltip_shorthand.js
@@ -0,0 +1,133 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let contentDoc;
+let inspector;
+let ruleView;
+let computedView;
+
+const PAGE_CONTENT = [
+  '<style type="text/css">',
+  '  #testElement {',
+  '    font: italic bold .8em/1.2 Arial;',
+  '  }',
+  '</style>',
+  '<div id="testElement">test element</div>'
+].join("\n");
+
+function test() {
+  waitForExplicitFinish();
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
+    contentDoc = content.document;
+    waitForFocus(createDocument, content);
+  }, true);
+
+  content.location = "data:text/html;charset=utf-8,font family shorthand tooltip test";
+}
+
+function createDocument() {
+  contentDoc.body.innerHTML = PAGE_CONTENT;
+
+  openRuleView((aInspector, aRuleView) => {
+    inspector = aInspector;
+    ruleView = aRuleView;
+    startTests();
+  });
+}
+
+function startTests() {
+  inspector.selection.setNode(contentDoc.querySelector("#testElement"));
+  inspector.once("inspector-updated", testRuleView);
+}
+
+function endTests() {
+  contentDoc = inspector = ruleView = computedView = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+function assertTooltipShownOn(tooltip, element, cb) {
+  // If there is indeed a show-on-hover on element, the xul panel will be shown
+  tooltip.panel.addEventListener("popupshown", function shown() {
+    tooltip.panel.removeEventListener("popupshown", shown, true);
+    cb();
+  }, true);
+  tooltip._showOnHover(element);
+}
+
+function testRuleView() {
+  info("Testing font-family tooltips in the rule view");
+
+  let panel = ruleView.previewTooltip.panel;
+
+  // Check that the rule view has a tooltip and that a XUL panel has been created
+  ok(ruleView.previewTooltip, "Tooltip instance exists");
+  ok(panel, "XUL panel exists");
+
+  // Get the computed font family property inside the font rule view
+  let propertyList = ruleView.element.querySelectorAll(".ruleview-propertylist");
+  let fontExpander = propertyList[1].querySelectorAll(".ruleview-expander")[0];
+  fontExpander.click();
+
+  let {valueSpan} = getRuleViewProperty("font-family");
+
+  // And verify that the tooltip gets shown on this property
+  assertTooltipShownOn(ruleView.previewTooltip, valueSpan, () => {
+    let description = panel.getElementsByTagName("description")[0];
+    is(description.style.fontFamily, "Arial", "Tooltips contains correct font-family style");
+
+    ruleView.previewTooltip.hide();
+
+    testComputedView();
+  });
+}
+
+function testComputedView() {
+  info("Testing font-family tooltips in the computed view");
+
+  inspector.sidebar.select("computedview");
+  computedView = inspector.sidebar.getWindowForTab("computedview").computedview.view;
+  let doc = computedView.styleDocument;
+
+  let panel = computedView.tooltip.panel;
+  let {valueSpan} = getComputedViewProperty("font-family");
+
+  assertTooltipShownOn(computedView.tooltip, valueSpan, () => {
+    let description = panel.getElementsByTagName("description")[0];
+    is(description.style.fontFamily, "Arial", "Tooltips contains correct font-family style");
+
+    computedView.tooltip.hide();
+
+    endTests();
+  });
+}
+
+function getRuleViewProperty(name) {
+  let prop = null;
+  [].forEach.call(ruleView.doc.querySelectorAll(".ruleview-computedlist"), property => {
+    let nameSpan = property.querySelector(".ruleview-propertyname");
+    let valueSpan = property.querySelector(".ruleview-propertyvalue");
+
+    if (nameSpan.textContent === name) {
+      prop = {nameSpan: nameSpan, valueSpan: valueSpan};
+    }
+  });
+  return prop;
+}
+
+function getComputedViewProperty(name) {
+  let prop = null;
+  [].forEach.call(computedView.styleDocument.querySelectorAll(".property-view"), property => {
+    let nameSpan = property.querySelector(".property-name");
+    let valueSpan = property.querySelector(".property-value");
+
+    if (nameSpan.textContent === name) {
+      prop = {nameSpan: nameSpan, valueSpan: valueSpan};
+    }
+  });
+  return prop;
+}
--- a/browser/themes/shared/devtools/common.css
+++ b/browser/themes/shared/devtools/common.css
@@ -169,16 +169,24 @@
 .devtools-tooltip-simple-text:first-child {
   margin-top: -4px;
 }
 
 .devtools-tooltip-simple-text:last-child {
   margin-bottom: -4px;
 }
 
+/* Tooltip: Font Family Previewer Text */
+.devtools-tooltip-font-previewer-text {
+  max-width: 400px;
+  line-height: 1.5;
+  font-size: 150%;
+  text-align: center;
+}
+
 /* Tooltip: Alert Icon */
 
 .devtools-tooltip-alert-icon {
   width: 32px;
   height: 32px;
   margin: 6px;
   -moz-margin-end: 20px;
 }
--- a/browser/themes/shared/devtools/dark-theme.css
+++ b/browser/themes/shared/devtools/dark-theme.css
@@ -307,16 +307,20 @@ div.CodeMirror span.eval-text {
   }
 }
 
 .theme-tooltip-panel .devtools-tooltip-simple-text {
   color: white;
   border-bottom: 1px solid #434850;
 }
 
+.theme-tooltip-panel .devtools-tooltip-font-previewer-text {
+  color: white;
+}
+
 .theme-tooltip-panel .devtools-tooltip-simple-text:last-child {
   border-bottom: 0;
 }
 
 .devtools-horizontal-splitter {
   border-bottom: 1px solid black;
 }
 
--- a/browser/themes/shared/devtools/light-theme.css
+++ b/browser/themes/shared/devtools/light-theme.css
@@ -316,16 +316,20 @@ div.CodeMirror span.eval-text {
   }
 }
 
 .theme-tooltip-panel .devtools-tooltip-simple-text {
   color: black;
   border-bottom: 1px solid #d9e1e8;
 }
 
+.theme-tooltip-panel .devtools-tooltip-font-previewer-text {
+  color: black;
+}
+
 .theme-tooltip-panel .devtools-tooltip-simple-text:last-child {
   border-bottom: 0;
 }
 
 .devtools-horizontal-splitter {
   border-bottom: 1px solid #aaa;
 }