зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1307481 - Part 4: Implements the Inline Tooltip widget. r=jdescottes
This commit is contained in:
Родитель
724677c3ab
Коммит
ad70ec2061
|
@ -9,6 +9,7 @@
|
|||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/widgets.css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/content/shared/widgets/color-widget.css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/inspector.css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/rules.css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/computed.css"/>
|
||||
|
|
|
@ -108,7 +108,7 @@ TextPropertyEditor.prototype = {
|
|||
this.element._textPropertyEditor = this;
|
||||
|
||||
this.container = createChild(this.element, "div", {
|
||||
class: "ruleview-propertycontainer"
|
||||
class: "ruleview-propertycontainer inline-tooltip-container"
|
||||
});
|
||||
|
||||
// The enable checkbox will disable or enable the rule.
|
||||
|
|
|
@ -40,102 +40,18 @@ const XHTML_NS = "http://www.w3.org/1999/xhtml";
|
|||
function ColorWidget(parentEl, rgb) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this.element = parentEl.ownerDocument.createElementNS(XHTML_NS, "div");
|
||||
this.parentEl = parentEl;
|
||||
|
||||
this.element.className = "colorwidget-container";
|
||||
this.element.innerHTML = `
|
||||
<div class="colorwidget-top">
|
||||
<div class="colorwidget-fill"></div>
|
||||
<div class="colorwidget-top-inner">
|
||||
<div class="colorwidget-color colorwidget-box">
|
||||
<div class="colorwidget-sat">
|
||||
<div class="colorwidget-val">
|
||||
<div class="colorwidget-dragger"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colorwidget-hue colorwidget-box">
|
||||
<div class="colorwidget-slider colorwidget-slider-control"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colorwidget-alpha colorwidget-checker colorwidget-box">
|
||||
<div class="colorwidget-alpha-inner">
|
||||
<div class="colorwidget-alpha-handle colorwidget-slider-control"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colorwidget-value">
|
||||
<select class="colorwidget-select">
|
||||
<option value="hex">Hex</option>
|
||||
<option value="rgba">RGBA</option>
|
||||
<option value="hsla">HSLA</option>
|
||||
</select>
|
||||
<div class="colorwidget-hex">
|
||||
<input class="colorwidget-hex-input"/>
|
||||
</div>
|
||||
<div class="colorwidget-rgba colorwidget-hidden">
|
||||
<input class="colorwidget-rgba-r" data-id="r" />
|
||||
<input class="colorwidget-rgba-g" data-id="g" />
|
||||
<input class="colorwidget-rgba-b" data-id="b" />
|
||||
<input class="colorwidget-rgba-a" data-id="a" />
|
||||
</div>
|
||||
<div class="colorwidget-hsla colorwidget-hidden">
|
||||
<input class="colorwidget-hsla-h" data-id="h" />
|
||||
<input class="colorwidget-hsla-s" data-id="s" />
|
||||
<input class="colorwidget-hsla-l" data-id="l" />
|
||||
<input class="colorwidget-hsla-a" data-id="a" />
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
this.onSelectValueChange = this.onSelectValueChange.bind(this);
|
||||
this.onHexInputChange = this.onHexInputChange.bind(this);
|
||||
this.onRgbaInputChange = this.onRgbaInputChange.bind(this);
|
||||
this.onHslaInputChange = this.onHslaInputChange.bind(this);
|
||||
|
||||
this.onAlphaSliderMove = this.onAlphaSliderMove.bind(this);
|
||||
this.onElementClick = this.onElementClick.bind(this);
|
||||
this.element.addEventListener("click", this.onElementClick);
|
||||
this.onDraggerMove = this.onDraggerMove.bind(this);
|
||||
this.onHexInputChange = this.onHexInputChange.bind(this);
|
||||
this.onHslaInputChange = this.onHslaInputChange.bind(this);
|
||||
this.onRgbaInputChange = this.onRgbaInputChange.bind(this);
|
||||
this.onSelectValueChange = this.onSelectValueChange.bind(this);
|
||||
this.onSliderMove = this.onSliderMove.bind(this);
|
||||
|
||||
this.parentEl.appendChild(this.element);
|
||||
|
||||
this.slider = this.element.querySelector(".colorwidget-hue");
|
||||
this.slideHelper = this.element.querySelector(".colorwidget-slider");
|
||||
ColorWidget.draggable(this.slider, this.onSliderMove.bind(this));
|
||||
|
||||
this.dragger = this.element.querySelector(".colorwidget-color");
|
||||
this.dragHelper = this.element.querySelector(".colorwidget-dragger");
|
||||
ColorWidget.draggable(this.dragger, this.onDraggerMove.bind(this));
|
||||
|
||||
this.alphaSlider = this.element.querySelector(".colorwidget-alpha");
|
||||
this.alphaSliderInner = this.element.querySelector(".colorwidget-alpha-inner");
|
||||
this.alphaSliderHelper = this.element.querySelector(".colorwidget-alpha-handle");
|
||||
ColorWidget.draggable(this.alphaSliderInner, this.onAlphaSliderMove.bind(this));
|
||||
|
||||
this.colorSelect = this.element.querySelector(".colorwidget-select");
|
||||
this.colorSelect.addEventListener("change", this.onSelectValueChange);
|
||||
|
||||
this.hexValue = this.element.querySelector(".colorwidget-hex");
|
||||
this.hexValueInput = this.element.querySelector(".colorwidget-hex-input");
|
||||
this.hexValueInput.addEventListener("input", this.onHexInputChange);
|
||||
|
||||
this.rgbaValue = this.element.querySelector(".colorwidget-rgba");
|
||||
this.rgbaValueInputs = {
|
||||
r: this.element.querySelector(".colorwidget-rgba-r"),
|
||||
g: this.element.querySelector(".colorwidget-rgba-g"),
|
||||
b: this.element.querySelector(".colorwidget-rgba-b"),
|
||||
a: this.element.querySelector(".colorwidget-rgba-a"),
|
||||
};
|
||||
this.rgbaValue.addEventListener("input", this.onRgbaInputChange);
|
||||
|
||||
this.hslaValue = this.element.querySelector(".colorwidget-hsla");
|
||||
this.hslaValueInputs = {
|
||||
h: this.element.querySelector(".colorwidget-hsla-h"),
|
||||
s: this.element.querySelector(".colorwidget-hsla-s"),
|
||||
l: this.element.querySelector(".colorwidget-hsla-l"),
|
||||
a: this.element.querySelector(".colorwidget-hsla-a"),
|
||||
};
|
||||
this.hslaValue.addEventListener("input", this.onHslaInputChange);
|
||||
this.initializeColorWidget();
|
||||
|
||||
if (rgb) {
|
||||
this.rgb = rgb;
|
||||
|
@ -291,7 +207,101 @@ ColorWidget.prototype = {
|
|||
rgb[3] + ")";
|
||||
},
|
||||
|
||||
initializeColorWidget: function () {
|
||||
this.parentEl.innerHTML = "";
|
||||
this.element = this.parentEl.ownerDocument.createElementNS(XHTML_NS, "div");
|
||||
|
||||
this.element.className = "colorwidget-container";
|
||||
this.element.innerHTML = `
|
||||
<div class="colorwidget-top">
|
||||
<div class="colorwidget-fill"></div>
|
||||
<div class="colorwidget-top-inner">
|
||||
<div class="colorwidget-color colorwidget-box">
|
||||
<div class="colorwidget-sat">
|
||||
<div class="colorwidget-val">
|
||||
<div class="colorwidget-dragger"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colorwidget-hue colorwidget-box">
|
||||
<div class="colorwidget-slider colorwidget-slider-control"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colorwidget-alpha colorwidget-checker colorwidget-box">
|
||||
<div class="colorwidget-alpha-inner">
|
||||
<div class="colorwidget-alpha-handle colorwidget-slider-control"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colorwidget-value">
|
||||
<select class="colorwidget-select">
|
||||
<option value="hex">Hex</option>
|
||||
<option value="rgba">RGBA</option>
|
||||
<option value="hsla">HSLA</option>
|
||||
</select>
|
||||
<div class="colorwidget-hex">
|
||||
<input class="colorwidget-hex-input"/>
|
||||
</div>
|
||||
<div class="colorwidget-rgba colorwidget-hidden">
|
||||
<input class="colorwidget-rgba-r" data-id="r" />
|
||||
<input class="colorwidget-rgba-g" data-id="g" />
|
||||
<input class="colorwidget-rgba-b" data-id="b" />
|
||||
<input class="colorwidget-rgba-a" data-id="a" />
|
||||
</div>
|
||||
<div class="colorwidget-hsla colorwidget-hidden">
|
||||
<input class="colorwidget-hsla-h" data-id="h" />
|
||||
<input class="colorwidget-hsla-s" data-id="s" />
|
||||
<input class="colorwidget-hsla-l" data-id="l" />
|
||||
<input class="colorwidget-hsla-a" data-id="a" />
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
this.element.addEventListener("click", this.onElementClick);
|
||||
|
||||
this.parentEl.appendChild(this.element);
|
||||
|
||||
this.slider = this.element.querySelector(".colorwidget-hue");
|
||||
this.slideHelper = this.element.querySelector(".colorwidget-slider");
|
||||
ColorWidget.draggable(this.slider, this.onSliderMove);
|
||||
|
||||
this.dragger = this.element.querySelector(".colorwidget-color");
|
||||
this.dragHelper = this.element.querySelector(".colorwidget-dragger");
|
||||
ColorWidget.draggable(this.dragger, this.onDraggerMove);
|
||||
|
||||
this.alphaSlider = this.element.querySelector(".colorwidget-alpha");
|
||||
this.alphaSliderInner = this.element.querySelector(".colorwidget-alpha-inner");
|
||||
this.alphaSliderHelper = this.element.querySelector(".colorwidget-alpha-handle");
|
||||
ColorWidget.draggable(this.alphaSliderInner, this.onAlphaSliderMove);
|
||||
|
||||
this.colorSelect = this.element.querySelector(".colorwidget-select");
|
||||
this.colorSelect.addEventListener("change", this.onSelectValueChange);
|
||||
|
||||
this.hexValue = this.element.querySelector(".colorwidget-hex");
|
||||
this.hexValueInput = this.element.querySelector(".colorwidget-hex-input");
|
||||
this.hexValueInput.addEventListener("input", this.onHexInputChange);
|
||||
|
||||
this.rgbaValue = this.element.querySelector(".colorwidget-rgba");
|
||||
this.rgbaValueInputs = {
|
||||
r: this.element.querySelector(".colorwidget-rgba-r"),
|
||||
g: this.element.querySelector(".colorwidget-rgba-g"),
|
||||
b: this.element.querySelector(".colorwidget-rgba-b"),
|
||||
a: this.element.querySelector(".colorwidget-rgba-a"),
|
||||
};
|
||||
this.rgbaValue.addEventListener("input", this.onRgbaInputChange);
|
||||
|
||||
this.hslaValue = this.element.querySelector(".colorwidget-hsla");
|
||||
this.hslaValueInputs = {
|
||||
h: this.element.querySelector(".colorwidget-hsla-h"),
|
||||
s: this.element.querySelector(".colorwidget-hsla-s"),
|
||||
l: this.element.querySelector(".colorwidget-hsla-l"),
|
||||
a: this.element.querySelector(".colorwidget-hsla-a"),
|
||||
};
|
||||
this.hslaValue.addEventListener("input", this.onHslaInputChange);
|
||||
},
|
||||
|
||||
show: function () {
|
||||
this.initializeColorWidget();
|
||||
this.element.classList.add("colorwidget-show");
|
||||
|
||||
this.slideHeight = this.slider.offsetHeight;
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
/* 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 EventEmitter = require("devtools/shared/event-emitter");
|
||||
|
||||
/**
|
||||
* The InlineTooltip can display widgets for the CSS Rules view in an
|
||||
* inline container.
|
||||
*
|
||||
* @param {Document} doc
|
||||
* The toolbox document to attach the InlineTooltip container.
|
||||
*/
|
||||
function InlineTooltip(doc) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this.doc = doc;
|
||||
|
||||
this.panel = this.doc.createElement("div");
|
||||
|
||||
this.topWindow = this._getTopWindow();
|
||||
}
|
||||
|
||||
InlineTooltip.prototype = {
|
||||
/**
|
||||
* Show the tooltip. It might be wise to append some content first if you
|
||||
* don't want the tooltip to be empty.
|
||||
*
|
||||
* @param {Node} anchor
|
||||
* Which node below which the tooltip should be shown.
|
||||
*/
|
||||
show(anchor) {
|
||||
anchor.parentNode.insertBefore(this.panel, anchor.nextSibling);
|
||||
|
||||
this.emit("shown");
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide the current tooltip.
|
||||
*/
|
||||
hide() {
|
||||
if (!this.isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.panel.parentNode.remove(this.panel);
|
||||
|
||||
this.emit("hidden");
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the tooltip is currently displayed.
|
||||
*
|
||||
* @return {Boolean} true if the tooltip is visible
|
||||
*/
|
||||
isVisible() {
|
||||
return typeof this.panel.parentNode !== "undefined" && this.panel.parentNode !== null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the HTML content of the tooltip panel
|
||||
*/
|
||||
clear() {
|
||||
this.panel.innerHTML = "";
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the content of this tooltip. Will first clear the tooltip and then
|
||||
* append the new content element.
|
||||
*
|
||||
* @param {DOMNode} content
|
||||
* A node that can be appended in the tooltip
|
||||
*/
|
||||
setContent(content) {
|
||||
this.clear();
|
||||
|
||||
this.panel.appendChild(content);
|
||||
},
|
||||
|
||||
get content() {
|
||||
return this.panel.firstChild;
|
||||
},
|
||||
|
||||
_getTopWindow: function () {
|
||||
return this.doc.defaultView;
|
||||
},
|
||||
|
||||
destroy() {
|
||||
this.hide();
|
||||
this.doc = null;
|
||||
this.panel = null;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = InlineTooltip;
|
|
@ -7,6 +7,9 @@
|
|||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
|
||||
const {HTMLTooltip} = require("devtools/client/shared/widgets/tooltip/HTMLTooltip");
|
||||
const InlineTooltip = require("devtools/client/shared/widgets/tooltip/InlineTooltip");
|
||||
|
||||
const INLINE_TOOLTIP_CLASS = "inline-tooltip-container";
|
||||
|
||||
/**
|
||||
* Base class for all (color, gradient, ...)-swatch based value editors inside
|
||||
|
@ -16,19 +19,30 @@ const {HTMLTooltip} = require("devtools/client/shared/widgets/tooltip/HTMLToolti
|
|||
* The document to attach the SwatchBasedEditorTooltip. This is either the toolbox
|
||||
* document if the tooltip is a popup tooltip or the panel's document if it is an
|
||||
* inline editor.
|
||||
* @param {String} stylesheet
|
||||
* The stylesheet to be used for the HTMLTooltip.
|
||||
* @param {Boolean} useInline
|
||||
* A boolean flag representing whether or not the InlineTooltip should be used.
|
||||
*/
|
||||
function SwatchBasedEditorTooltip(document, stylesheet) {
|
||||
function SwatchBasedEditorTooltip(document, stylesheet, useInline) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this.useInline = useInline;
|
||||
|
||||
// Creating a tooltip instance
|
||||
// This one will consume outside clicks as it makes more sense to let the user
|
||||
// close the tooltip by clicking out
|
||||
// It will also close on <escape> and <enter>
|
||||
this.tooltip = new HTMLTooltip(document, {
|
||||
type: "arrow",
|
||||
consumeOutsideClicks: true,
|
||||
useXulWrapper: true,
|
||||
stylesheet
|
||||
});
|
||||
if (useInline) {
|
||||
this.tooltip = new InlineTooltip(document);
|
||||
} else {
|
||||
// This one will consume outside clicks as it makes more sense to let the user
|
||||
// close the tooltip by clicking out
|
||||
// It will also close on <escape> and <enter>
|
||||
this.tooltip = new HTMLTooltip(document, {
|
||||
type: "arrow",
|
||||
consumeOutsideClicks: true,
|
||||
useXulWrapper: true,
|
||||
stylesheet
|
||||
});
|
||||
}
|
||||
|
||||
// By default, swatch-based editor tooltips revert value change on <esc> and
|
||||
// commit value change on <enter>
|
||||
|
@ -73,9 +87,13 @@ SwatchBasedEditorTooltip.prototype = {
|
|||
* immediately if there is no currently active swatch.
|
||||
*/
|
||||
show: function () {
|
||||
if (this.activeSwatch) {
|
||||
let tooltipAnchor = this.useInline ?
|
||||
this.activeSwatch.closest(`.${INLINE_TOOLTIP_CLASS}`) :
|
||||
this.activeSwatch;
|
||||
|
||||
if (tooltipAnchor) {
|
||||
let onShown = this.tooltip.once("shown");
|
||||
this.tooltip.show(this.activeSwatch, "topcenter bottomleft");
|
||||
this.tooltip.show(tooltipAnchor, "topcenter bottomleft");
|
||||
|
||||
// When the tooltip is closed by clicking outside the panel we want to
|
||||
// commit any changes.
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
const Services = require("Services");
|
||||
const {Task} = require("devtools/shared/task");
|
||||
const {colorUtils} = require("devtools/shared/css/color");
|
||||
const {ColorWidget} = require("devtools/client/shared/widgets/ColorWidget");
|
||||
const {Spectrum} = require("devtools/client/shared/widgets/Spectrum");
|
||||
const SwatchBasedEditorTooltip = require("devtools/client/shared/widgets/tooltip/SwatchBasedEditorTooltip");
|
||||
const {LocalizationHelper} = require("devtools/shared/l10n");
|
||||
|
@ -38,9 +39,10 @@ function SwatchColorPickerTooltip(document,
|
|||
inspector,
|
||||
{supportsCssColor4ColorFunction}) {
|
||||
let stylesheet = NEW_COLOR_WIDGET ?
|
||||
"chrome://devtools/content/shared/widgets/color-widget.css" :
|
||||
null :
|
||||
"chrome://devtools/content/shared/widgets/spectrum.css";
|
||||
SwatchBasedEditorTooltip.call(this, document, stylesheet);
|
||||
let tooltipDocument = NEW_COLOR_WIDGET ? inspector.panelDoc : document;
|
||||
SwatchBasedEditorTooltip.call(this, tooltipDocument, stylesheet, NEW_COLOR_WIDGET);
|
||||
|
||||
this.inspector = inspector;
|
||||
|
||||
|
@ -62,9 +64,20 @@ SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.pr
|
|||
|
||||
let container = doc.createElementNS(XHTML_NS, "div");
|
||||
container.id = "spectrum-tooltip";
|
||||
let spectrumNode = doc.createElementNS(XHTML_NS, "div");
|
||||
spectrumNode.id = "spectrum";
|
||||
container.appendChild(spectrumNode);
|
||||
|
||||
let widget;
|
||||
let node = doc.createElementNS(XHTML_NS, "div");
|
||||
|
||||
if (NEW_COLOR_WIDGET) {
|
||||
node.id = "colorwidget";
|
||||
container.appendChild(node);
|
||||
widget = new ColorWidget(node, color);
|
||||
} else {
|
||||
node.id = "spectrum";
|
||||
container.appendChild(node);
|
||||
widget = new Spectrum(node, color);
|
||||
}
|
||||
|
||||
let eyedropper = doc.createElementNS(XHTML_NS, "button");
|
||||
eyedropper.id = "eyedropper-button";
|
||||
eyedropper.className = "devtools-button";
|
||||
|
@ -74,23 +87,15 @@ SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.pr
|
|||
eyedropper.style.pointerEvents = "auto";
|
||||
container.appendChild(eyedropper);
|
||||
|
||||
let spectrum;
|
||||
if (NEW_COLOR_WIDGET) {
|
||||
this.tooltip.setContent(container, { width: 218, height: 271 });
|
||||
const {ColorWidget} = require("devtools/client/shared/widgets/ColorWidget");
|
||||
spectrum = new ColorWidget(spectrumNode, color);
|
||||
} else {
|
||||
this.tooltip.setContent(container, { width: 218, height: 224 });
|
||||
spectrum = new Spectrum(spectrumNode, color);
|
||||
}
|
||||
this.tooltip.setContent(container, { width: 218, height: 224 });
|
||||
|
||||
// Wait for the tooltip to be shown before calling spectrum.show
|
||||
// Wait for the tooltip to be shown before calling widget.show
|
||||
// as it expect to be visible in order to compute DOM element sizes.
|
||||
this.tooltip.once("shown", () => {
|
||||
spectrum.show();
|
||||
widget.show();
|
||||
});
|
||||
|
||||
return spectrum;
|
||||
return widget;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -100,6 +105,7 @@ SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.pr
|
|||
show: Task.async(function* () {
|
||||
// Call then parent class' show function
|
||||
yield SwatchBasedEditorTooltip.prototype.show.call(this);
|
||||
|
||||
// Then set spectrum's color and listen to color changes to preview them
|
||||
if (this.activeSwatch) {
|
||||
this.currentSwatchColor = this.activeSwatch.nextSibling;
|
||||
|
|
|
@ -9,6 +9,7 @@ DevToolsModules(
|
|||
'EventTooltipHelper.js',
|
||||
'HTMLTooltip.js',
|
||||
'ImageTooltipHelper.js',
|
||||
'InlineTooltip.js',
|
||||
'SwatchBasedEditorTooltip.js',
|
||||
'SwatchColorPickerTooltip.js',
|
||||
'SwatchCubicBezierTooltip.js',
|
||||
|
|
Загрузка…
Ссылка в новой задаче