Bug 1283454 - migrate MDN docs tooltip to use HTML;r=ochameau

MozReview-Commit-ID: 50DceNmgGAQ

--HG--
extra : rebase_source : 669214f693c863eab72c24d3be9936fc049dd365
This commit is contained in:
Julian Descottes 2016-07-05 14:39:52 +02:00
Родитель a3203be2b0
Коммит 6bc3c91358
12 изменённых файлов: 208 добавлений и 194 удалений

Просмотреть файл

@ -12,7 +12,7 @@
*
* This file tests that:
* - clicking the context menu item shows the tooltip
* - pressing "Escape" while the tooltip is showing hides the tooltip
* - the tooltip content matches the property name for which the context menu was opened
*/
"use strict";
@ -36,10 +36,7 @@ add_task(function* () {
yield addTab("data:text/html;charset=utf8," + encodeURIComponent(TEST_DOC));
let {inspector, view} = yield openRuleView();
yield selectNode("div", inspector);
yield testShowAndHideMdnTooltip(view);
});
function* testShowMdnTooltip(view) {
setBaseCssDocsUrl(URL_ROOT);
info("Setting the popupNode for the MDN docs tooltip");
@ -57,30 +54,8 @@ function* testShowMdnTooltip(view) {
menuitemShowMdnDocs.click();
yield onShown;
ok(true, "The MDN docs tooltip was shown");
}
/**
* Test that:
* - the MDN tooltip is shown when we click the context menu item
* - the tooltip's contents have been initialized (we don't fully
* test this here, as it's fully tested with the tooltip test code)
* - the tooltip is hidden when we press Escape
*/
function* testShowAndHideMdnTooltip(view) {
yield testShowMdnTooltip(view);
info("Quick check that the tooltip contents are set");
let cssDocs = view.tooltips.cssDocs;
// FIXME: Remove the comment below when bug 1246896 is fixed.
/* eslint-disable mozilla/no-cpows-in-tests */
let tooltipDocument = cssDocs.tooltip.content.contentDocument;
let h1 = tooltipDocument.getElementById("property-name");
let h1 = cssDocs.tooltip.container.querySelector(".mdn-property-name");
is(h1.textContent, PROPERTYNAME, "The MDN docs tooltip h1 is correct");
info("Simulate pressing the 'Escape' key");
let onHidden = cssDocs.tooltip.once("hidden");
EventUtils.sendKey("escape");
yield onHidden;
ok(true, "The MDN docs tooltip was hidden on pressing 'escape'");
}
});

Просмотреть файл

@ -0,0 +1,51 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that the CssDocs tooltip of the ruleview can be closed when pressing the Escape
* key.
*/
"use strict";
const {setBaseCssDocsUrl} =
require("devtools/client/shared/widgets/MdnDocsWidget");
const PROPERTYNAME = "color";
const TEST_URI = `
<html>
<body>
<div style="color: red">
Test "Show MDN Docs" closes on escape
</div>
</body>
</html>
`;
/**
* Test that the tooltip is hidden when we press Escape
*/
add_task(function* () {
yield addTab("data:text/html;charset=utf8," + encodeURIComponent(TEST_URI));
let {inspector, view} = yield openRuleView();
yield selectNode("div", inspector);
setBaseCssDocsUrl(URL_ROOT);
info("Retrieve a valid anchor for the CssDocs tooltip");
let {nameSpan} = getRuleViewProperty(view, "element", PROPERTYNAME);
info("Showing the MDN docs tooltip");
let onShown = view.tooltips.cssDocs.tooltip.once("shown");
view.tooltips.cssDocs.show(nameSpan, PROPERTYNAME);
yield onShown;
ok(true, "The MDN docs tooltip was shown");
info("Simulate pressing the 'Escape' key");
let onHidden = view.tooltips.cssDocs.tooltip.once("hidden");
EventUtils.sendKey("escape");
yield onHidden;
ok(true, "The MDN docs tooltip was hidden on pressing 'escape'");
});

Просмотреть файл

@ -19,10 +19,12 @@ const {
setImageTooltip,
setBrokenImageTooltip,
} = require("devtools/client/shared/widgets/tooltip/ImageTooltipHelper");
const {
CssDocsTooltip,
} = require("devtools/client/shared/widgets/tooltip/CssDocsTooltip");
const {
SwatchColorPickerTooltip,
SwatchCubicBezierTooltip,
CssDocsTooltip,
SwatchFilterTooltip
} = require("devtools/client/shared/widgets/Tooltip");
const EventEmitter = require("devtools/shared/event-emitter");
@ -276,10 +278,10 @@ TooltipsOverlay.prototype = {
return;
}
let panelDoc = this.view.inspector.panelDoc;
let { toolbox } = this.view.inspector;
// Image, fonts, ... preview tooltip
this.previewTooltip = new HTMLTooltip(this.view.inspector.toolbox, {
this.previewTooltip = new HTMLTooltip(toolbox, {
type: "arrow",
useXulWrapper: true
});
@ -287,11 +289,10 @@ TooltipsOverlay.prototype = {
this._onPreviewTooltipTargetHover.bind(this));
// MDN CSS help tooltip
this.cssDocs = new CssDocsTooltip(panelDoc);
this.cssDocs = new CssDocsTooltip(toolbox);
if (this.isRuleView) {
// Color picker tooltip
let { toolbox } = this.view.inspector;
this.colorPicker = new SwatchColorPickerTooltip(toolbox);
// Cubic bezier tooltip
this.cubicBezier = new SwatchCubicBezierTooltip(toolbox);
@ -393,7 +394,7 @@ TooltipsOverlay.prototype = {
this.cubicBezier.hide();
}
if (this.isRuleView && this.cssDocs.tooltip.isShown()) {
if (this.isRuleView && this.cssDocs.tooltip.isVisible()) {
this.cssDocs.hide();
}

Просмотреть файл

@ -128,7 +128,6 @@ devtools.jar:
content/framework/connect/connect.js (framework/connect/connect.js)
content/shared/widgets/graphs-frame.xhtml (shared/widgets/graphs-frame.xhtml)
content/shared/widgets/cubic-bezier.css (shared/widgets/cubic-bezier.css)
content/shared/widgets/mdn-docs-frame.xhtml (shared/widgets/mdn-docs-frame.xhtml)
content/shared/widgets/mdn-docs.css (shared/widgets/mdn-docs.css)
content/shared/widgets/filter-widget.css (shared/widgets/filter-widget.css)
content/shared/widgets/spectrum.css (shared/widgets/spectrum.css)

Просмотреть файл

@ -20,12 +20,8 @@
"use strict";
const {CssDocsTooltip} = require("devtools/client/shared/widgets/Tooltip");
const {setBaseCssDocsUrl, MdnDocsWidget} = require("devtools/client/shared/widgets/MdnDocsWidget");
// frame to load the tooltip into
const MDN_DOCS_TOOLTIP_FRAME = "chrome://devtools/content/shared/widgets/mdn-docs-frame.xhtml";
/**
* Test properties
*
@ -45,14 +41,16 @@ const BASIC_EXPECTED_SYNTAX = [{type: "comment", text: "/* The part we want */
{type: "property-value", text: "is-the-part-we-want"},
{type: "text", text: ";"}];
const URI_PARAMS = "?utm_source=mozilla&utm_medium=firefox-inspector&utm_campaign=default";
const URI_PARAMS =
"?utm_source=mozilla&utm_medium=firefox-inspector&utm_campaign=default";
add_task(function* () {
setBaseCssDocsUrl(TEST_URI_ROOT);
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", MDN_DOCS_TOOLTIP_FRAME);
let widget = new MdnDocsWidget(win.document);
let [host, win] = yield createHost("bottom", "data:text/html," +
"<div class='mdn-container'></div>");
let widget = new MdnDocsWidget(win.document.querySelector("div"));
yield testTheBasics(widget);

Просмотреть файл

@ -21,11 +21,10 @@
"use strict";
const {CssDocsTooltip} = require("devtools/client/shared/widgets/Tooltip");
const {setBaseCssDocsUrl, MdnDocsWidget} = require("devtools/client/shared/widgets/MdnDocsWidget");
// frame to load the tooltip into
const MDN_DOCS_TOOLTIP_FRAME = "chrome://devtools/content/shared/widgets/mdn-docs-frame.xhtml";
const {
setBaseCssDocsUrl,
MdnDocsWidget
} = require("devtools/client/shared/widgets/MdnDocsWidget");
const BASIC_EXPECTED_SUMMARY = "A summary of the property.";
const BASIC_EXPECTED_SYNTAX = [{type: "comment", text: "/* The part we want */"},
@ -100,8 +99,9 @@ add_task(function* () {
setBaseCssDocsUrl(TEST_URI_ROOT);
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", MDN_DOCS_TOOLTIP_FRAME);
let widget = new MdnDocsWidget(win.document);
let [host, win] = yield createHost("bottom", "data:text/html," +
"<div class='mdn-container'></div>");
let widget = new MdnDocsWidget(win.document.querySelector("div"));
for (let {desc, docsPageUrl, expectedContents} of TEST_DATA) {
info(desc);
@ -112,21 +112,10 @@ add_task(function* () {
gBrowser.removeCurrentTab();
});
function* testNonExistentPage(widget) {
info("Test a property for which we don't have a page");
yield widget.loadCssDocs("i-dont-exist.html");
checkTooltipContents(widget.elements, {
propertyName: "i-dont-exist.html",
summary: ERROR_MESSAGE,
syntax: ""
});
}
/*
* Utility function to check content of the tooltip.
*/
function checkTooltipContents(doc, expected) {
is(doc.heading.textContent,
expected.propertyName,
"Property name is correct");

Просмотреть файл

@ -29,6 +29,8 @@ const defer = require("devtools/shared/defer");
const {getCSSLexer} = require("devtools/shared/css-lexer");
const {gDevTools} = require("devtools/client/framework/devtools");
const XHTML_NS = "http://www.w3.org/1999/xhtml";
// Parameters for the XHR request
// see https://developer.mozilla.org/en-US/docs/MDN/Kuma/API#Document_parameters
const XHR_PARAMS = "?raw&macros";
@ -87,7 +89,7 @@ function appendSyntaxHighlightedCSS(cssText, parentElement) {
* Create a SPAN node with the given text content and class.
*/
function createStyledNode(textContent, className) {
let newNode = doc.createElement("span");
let newNode = doc.createElementNS(XHTML_NS, "span");
newNode.classList.add(className);
newNode.textContent = textContent;
return newNode;
@ -224,9 +226,7 @@ exports.getCssDocs = getCssDocs;
/**
* The MdnDocsWidget is used by tooltip code that needs to display docs
* from MDN in a tooltip. The tooltip code loads a document that contains the
* basic structure of a docs tooltip (loaded from mdn-docs-frame.xhtml),
* and passes this document into the widget's constructor.
* from MDN in a tooltip.
*
* In the constructor, the widget does some general setup that's not
* dependent on the particular item we need docs for.
@ -234,22 +234,31 @@ exports.getCssDocs = getCssDocs;
* After that, when the tooltip code needs to display docs for an item, it
* asks the widget to retrieve the docs and update the document with them.
*
* @param {Document} tooltipDocument
* A DOM document. The widget expects the document to have a particular
* structure.
* @param {Element} tooltipContainer
* A DOM element where the MdnDocs widget markup should be created.
*/
function MdnDocsWidget(tooltipDocument) {
function MdnDocsWidget(tooltipContainer) {
tooltipContainer.innerHTML =
`<header>
<h1 class="mdn-property-name theme-fg-color5"></h1>
</header>
<div class="mdn-property-info">
<div class="mdn-summary"></div>
<pre class="mdn-syntax devtools-monospace"></pre>
</div>
<footer>
<a class="mdn-visit-page theme-link" href="#">Visit MDN (placeholder)</a>
</footer>`;
// fetch all the bits of the document that we will manipulate later
this.elements = {
heading: tooltipDocument.getElementById("property-name"),
summary: tooltipDocument.getElementById("summary"),
syntax: tooltipDocument.getElementById("syntax"),
info: tooltipDocument.getElementById("property-info"),
linkToMdn: tooltipDocument.getElementById("visit-mdn-page")
heading: tooltipContainer.querySelector(".mdn-property-name"),
summary: tooltipContainer.querySelector(".mdn-summary"),
syntax: tooltipContainer.querySelector(".mdn-syntax"),
info: tooltipContainer.querySelector(".mdn-property-info"),
linkToMdn: tooltipContainer.querySelector(".mdn-visit-page")
};
this.doc = tooltipDocument;
// get the localized string for the link text
this.elements.linkToMdn.textContent =
l10n.strings.GetStringFromName("docsTooltip.visitMDN");
@ -357,7 +366,6 @@ MdnDocsWidget.prototype = {
destroy: function () {
this.elements = null;
this.doc = null;
}
};

Просмотреть файл

@ -9,7 +9,6 @@ const defer = require("devtools/shared/defer");
const {Spectrum} = require("devtools/client/shared/widgets/Spectrum");
const {CubicBezierWidget} =
require("devtools/client/shared/widgets/CubicBezierWidget");
const {MdnDocsWidget} = require("devtools/client/shared/widgets/MdnDocsWidget");
const {CSSFilterEditorWidget} = require("devtools/client/shared/widgets/FilterWidget");
const {TooltipToggle} = require("devtools/client/shared/widgets/tooltip/TooltipToggle");
const EventEmitter = require("devtools/shared/event-emitter");
@ -33,9 +32,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "VariablesViewController",
"resource://devtools/client/shared/widgets/VariablesViewController.jsm");
const XHTML_NS = "http://www.w3.org/1999/xhtml";
const MDN_DOCS_FRAME = "chrome://devtools/content/shared/widgets/mdn-docs-frame.xhtml";
const ESCAPE_KEYCODE = Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE;
const RETURN_KEYCODE = Ci.nsIDOMKeyEvent.DOM_VK_RETURN;
const POPUP_EVENTS = ["shown", "hidden", "showing", "hiding"];
/**
@ -553,32 +550,6 @@ Tooltip.prototype = {
this.content = iframe;
return def.promise;
},
/**
* Set the content of this tooltip to the MDN docs widget.
*
* This is called when the tooltip is first constructed.
*
* @return {promise} A promise which is resolved with an MdnDocsWidget.
*
* It loads the tooltip's structure from a separate XHTML file
* into an iframe. When the iframe is loaded it constructs
* an MdnDocsWidget and passes that into resolve.
*
* The caller can use the MdnDocsWidget to update the tooltip's
* UI with new content each time the tooltip is shown.
*/
setMdnDocsContent: function () {
let dimensions = {width: "410", height: "300"};
return this.setIFrameContent(dimensions, MDN_DOCS_FRAME).then(onLoaded);
function onLoaded(iframe) {
let win = iframe.contentWindow.wrappedJSObject;
// create an MdnDocsWidget, initializing it with the content document
let widget = new MdnDocsWidget(win.document);
return widget;
}
}
};
@ -1004,45 +975,6 @@ Heritage.extend(SwatchBasedEditorTooltip.prototype, {
}
});
/**
* Tooltip for displaying docs for CSS properties from MDN.
*
* @param {XULDocument} doc
*/
function CssDocsTooltip(doc) {
this.tooltip = new Tooltip(doc, {
consumeOutsideClick: true,
closeOnKeys: [ESCAPE_KEYCODE, RETURN_KEYCODE],
noAutoFocus: false
});
this.widget = this.tooltip.setMdnDocsContent();
}
module.exports.CssDocsTooltip = CssDocsTooltip;
CssDocsTooltip.prototype = {
/**
* Load CSS docs for the given property,
* then display the tooltip.
*/
show: function (anchor, propertyName) {
function loadCssDocs(widget) {
return widget.loadCssDocs(propertyName);
}
this.widget.then(loadCssDocs);
this.tooltip.show(anchor, "topcenter bottomleft");
},
hide: function () {
this.tooltip.hide();
},
destroy: function () {
this.tooltip.destroy();
}
};
/**
* The swatch-based css filter tooltip class is a specific class meant to be
* used along with rule-view's generated css filter swatches.

Просмотреть файл

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" href="chrome://devtools/content/shared/widgets/mdn-docs.css" type="text/css"/>
<script type="application/javascript;version=1.8" src="chrome://devtools/content/shared/theme-switching.js"/>
</head>
<body class="theme-body">
<div id = "container">
<header>
<h1 id="property-name" class="theme-fg-color5"></h1>
</header>
<div id="property-info">
<div id="summary"></div>
<pre id="syntax" class="devtools-monospace"></pre>
</div>
<footer>
<a id="visit-mdn-page" class="theme-link" href="#">Visit MDN (placeholder)</a>
</footer>
</div>
</body>
</html>

Просмотреть файл

@ -2,40 +2,38 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#visit-mdn-page {
display: inline-block;
padding: 1em 0;
}
html, body, #container {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
#container {
.mdn-container {
height: 300px;
margin: 4px;
overflow: auto;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
header, footer {
.mdn-container header,
.mdn-container footer {
flex: 1;
padding: 0 1em;
}
#property-info {
.mdn-property-info {
flex: 10;
padding: 0 1em;
overflow: auto;
transition: opacity 400ms ease-in;
}
#syntax {
.mdn-syntax {
margin-top: 1em;
}
.devtools-throbber {
opacity: 0;
align-self: center;
opacity: 0;
}
.mdn-visit-page {
display: inline-block;
padding: 1em 0;
}

Просмотреть файл

@ -0,0 +1,95 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {HTMLTooltip} = require("devtools/client/shared/widgets/HTMLTooltip");
const {MdnDocsWidget} = require("devtools/client/shared/widgets/MdnDocsWidget");
const XHTML_NS = "http://www.w3.org/1999/xhtml";
loader.lazyRequireGetter(this, "KeyShortcuts",
"devtools/client/shared/key-shortcuts", true);
const TOOLTIP_WIDTH = 418;
const TOOLTIP_HEIGHT = 308;
/**
* Tooltip for displaying docs for CSS properties from MDN.
*
* @param {Toolbox} toolbox
* Toolbox used to create the tooltip.
*/
function CssDocsTooltip(toolbox) {
this.tooltip = new HTMLTooltip(toolbox, {
type: "arrow",
consumeOutsideClicks: true,
autofocus: true,
useXulWrapper: true,
stylesheet: "chrome://devtools/content/shared/widgets/mdn-docs.css",
});
this.widget = this.setMdnDocsContent();
// Initialize keyboard shortcuts
this.shortcuts = new KeyShortcuts({ window: toolbox.doc.defaultView });
this._onShortcut = this._onShortcut.bind(this);
this.shortcuts.on("Escape", this._onShortcut);
this.shortcuts.on("Return", this._onShortcut);
}
module.exports.CssDocsTooltip = CssDocsTooltip;
CssDocsTooltip.prototype = {
/**
* Load CSS docs for the given property,
* then display the tooltip.
*/
show: function (anchor, propertyName) {
this.tooltip.once("shown", () => {
this.widget.loadCssDocs(propertyName);
});
this.tooltip.show(anchor);
},
hide: function () {
this.tooltip.hide();
},
_onShortcut: function (shortcut, event) {
if (!this.tooltip.isVisible()) {
return;
}
event.stopPropagation();
if (shortcut === "Return") {
// If user is pressing return, do not prevent default and delay hiding the tooltip
// in case the focus is on the "Visit MDN page" link.
this.tooltip.doc.defaultView.setTimeout(this.hide.bind(this), 0);
} else {
// For any other key, preventDefault() and hide straight away.
event.preventDefault();
this.hide();
}
},
/**
* Set the content of this tooltip to the MDN docs widget. This is called when the
* tooltip is first constructed.
* The caller can use the MdnDocsWidget to update the tooltip's UI with new content
* each time the tooltip is shown.
*
* @return {MdnDocsWidget} the created MdnDocsWidget instance.
*/
setMdnDocsContent: function () {
let container = this.tooltip.doc.createElementNS(XHTML_NS, "div");
container.setAttribute("class", "mdn-container theme-body");
this.tooltip.setContent(container, {width: TOOLTIP_WIDTH, height: TOOLTIP_HEIGHT});
return new MdnDocsWidget(container);
},
destroy: function () {
this.shortcuts.destroy();
this.tooltip.destroy();
}
};

Просмотреть файл

@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'CssDocsTooltip.js',
'EventTooltipHelper.js',
'ImageTooltipHelper.js',
'TooltipToggle.js',