From c660dc102141c52478bce4324227fc0ee9b012ed Mon Sep 17 00:00:00 2001 From: Alexandre Poirot Date: Mon, 11 Jul 2016 01:26:02 -0700 Subject: [PATCH] Bug 1267414 - Convert color picker, cubic bezier and filter widgets to HTML Tooltip. r=jdescottes --HG-- rename : devtools/client/themes/spectrum.css => devtools/client/shared/widgets/spectrum.css --- .../test/browser_rules_authored_color.js | 2 +- .../rules/test/browser_rules_colorUnit.js | 2 +- ..._rules_colorpicker-and-image-tooltip_01.js | 2 +- ..._rules_colorpicker-and-image-tooltip_02.js | 2 +- ...owser_rules_colorpicker-commit-on-ENTER.js | 2 +- ...rules_colorpicker-release-outside-frame.js | 2 +- ...browser_rules_colorpicker-revert-on-ESC.js | 4 +- .../browser_rules_edit-value-after-name_03.js | 2 +- .../rules/test/browser_rules_eyedropper.js | 5 +- ...es_filtereditor-appears-on-swatch-click.js | 1 - ...wser_rules_filtereditor-commit-on-ENTER.js | 2 +- ...rowser_rules_filtereditor-revert-on-ESC.js | 8 +- devtools/client/inspector/rules/test/head.js | 10 +- .../shared/style-inspector-overlays.js | 19 +- .../client/inspector/shared/test/browser.ini | 1 - .../browser_styleinspector_tooltip-size.js | 11 +- devtools/client/jar.mn | 5 +- .../client/locales/en-US/filterwidget.dtd | 24 -- .../locales/en-US/filterwidget.properties | 22 ++ .../shared/test/browser_cubic-bezier-01.js | 9 +- .../shared/test/browser_cubic-bezier-02.js | 14 +- .../shared/test/browser_cubic-bezier-03.js | 7 +- .../shared/test/browser_cubic-bezier-04.js | 7 +- .../shared/test/browser_cubic-bezier-05.js | 7 +- .../shared/test/browser_cubic-bezier-06.js | 7 +- .../shared/test/browser_filter-editor-01.js | 6 +- .../shared/test/browser_filter-editor-02.js | 6 +- .../shared/test/browser_filter-editor-03.js | 7 +- .../shared/test/browser_filter-editor-04.js | 6 +- .../shared/test/browser_filter-editor-05.js | 6 +- .../shared/test/browser_filter-editor-06.js | 7 +- .../shared/test/browser_filter-editor-07.js | 7 +- .../shared/test/browser_filter-editor-08.js | 6 +- .../shared/test/browser_filter-editor-09.js | 6 +- .../shared/test/browser_filter-editor-10.js | 6 +- .../shared/test/browser_filter-presets-01.js | 7 +- .../shared/test/browser_filter-presets-02.js | 7 +- .../shared/test/browser_filter-presets-03.js | 7 +- .../client/shared/test/browser_spectrum.js | 54 ++-- .../shared/widgets/CubicBezierWidget.js | 60 ++-- .../client/shared/widgets/FilterWidget.js | 60 +++- devtools/client/shared/widgets/Spectrum.js | 20 +- devtools/client/shared/widgets/Tooltip.js | 290 +++++++++--------- .../shared/widgets/cubic-bezier-frame.xhtml | 25 -- .../client/shared/widgets/cubic-bezier.css | 31 +- .../client/shared/widgets/filter-frame.xhtml | 40 --- .../client/shared/widgets/filter-widget.css | 23 +- .../shared/widgets/spectrum-frame.xhtml | 23 -- .../{themes => shared/widgets}/spectrum.css | 0 devtools/client/themes/tooltips.css | 1 - 50 files changed, 382 insertions(+), 506 deletions(-) delete mode 100644 devtools/client/locales/en-US/filterwidget.dtd delete mode 100644 devtools/client/shared/widgets/cubic-bezier-frame.xhtml delete mode 100644 devtools/client/shared/widgets/filter-frame.xhtml delete mode 100644 devtools/client/shared/widgets/spectrum-frame.xhtml rename devtools/client/{themes => shared/widgets}/spectrum.css (100%) diff --git a/devtools/client/inspector/rules/test/browser_rules_authored_color.js b/devtools/client/inspector/rules/test/browser_rules_authored_color.js index 40c7bf75996e..9501f9fc0ee2 100644 --- a/devtools/client/inspector/rules/test/browser_rules_authored_color.js +++ b/devtools/client/inspector/rules/test/browser_rules_authored_color.js @@ -47,7 +47,7 @@ add_task(function* () { value: "rgb(0, 255, 0)" }); - let spectrum = yield cPicker.spectrum; + let spectrum = cPicker.spectrum; let onHidden = cPicker.tooltip.once("hidden"); // Validating the color change ends up updating the rule view twice let onRuleViewChanged = waitForNEvents(view, "ruleview-changed", 2); diff --git a/devtools/client/inspector/rules/test/browser_rules_colorUnit.js b/devtools/client/inspector/rules/test/browser_rules_colorUnit.js index 3ff6495e222e..6b01885e9f5f 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorUnit.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorUnit.js @@ -52,7 +52,7 @@ function* basicTest(view, name, result) { value: "rgb(0, 255, 0)" }); - let spectrum = yield cPicker.spectrum; + let spectrum = cPicker.spectrum; let onHidden = cPicker.tooltip.once("hidden"); // Validating the color change ends up updating the rule view twice let onRuleViewChanged = waitForNEvents(view, "ruleview-changed", 2); diff --git a/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_01.js b/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_01.js index 9d312f1b764d..416c16d1943d 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_01.js @@ -44,7 +44,7 @@ function* testImageTooltipAfterColorChange(swatch, url, ruleView) { value: 'url("chrome://global/skin/icons/warning-64.png"), linear-gradient(rgb(0, 0, 0), rgb(255, 0, 102) 400px)' }); - let spectrum = yield picker.spectrum; + let spectrum = picker.spectrum; let onHidden = picker.tooltip.once("hidden"); let onModifications = ruleView.once("ruleview-changed"); EventUtils.sendKey("RETURN", spectrum.element.ownerDocument.defaultView); diff --git a/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_02.js b/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_02.js index 7414056b40b7..c5cc55c9bdcc 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_02.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_02.js @@ -42,7 +42,7 @@ function* testColorChangeIsntRevertedWhenOtherTooltipIsShown(ruleView) { value: "rgb(0, 0, 0)" }); - let spectrum = yield picker.spectrum; + let spectrum = picker.spectrum; let onModifications = waitForNEvents(ruleView, "ruleview-changed", 2); let onHidden = picker.tooltip.once("hidden"); diff --git a/devtools/client/inspector/rules/test/browser_rules_colorpicker-commit-on-ENTER.js b/devtools/client/inspector/rules/test/browser_rules_colorpicker-commit-on-ENTER.js index 6fbf87ec91fd..8370fe07bc79 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-commit-on-ENTER.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-commit-on-ENTER.js @@ -45,7 +45,7 @@ function* testPressingEnterCommitsChanges(swatch, ruleView) { "The text of the border css property was updated"); let onModified = ruleView.once("ruleview-changed"); - let spectrum = yield cPicker.spectrum; + let spectrum = cPicker.spectrum; let onHidden = cPicker.tooltip.once("hidden"); EventUtils.sendKey("RETURN", spectrum.element.ownerDocument.defaultView); yield onHidden; diff --git a/devtools/client/inspector/rules/test/browser_rules_colorpicker-release-outside-frame.js b/devtools/client/inspector/rules/test/browser_rules_colorpicker-release-outside-frame.js index 0fbe7e2d984f..3dfa2f22476d 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-release-outside-frame.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-release-outside-frame.js @@ -17,7 +17,7 @@ add_task(function* () { .querySelector(".ruleview-colorswatch"); let picker = yield openColorPickerForSwatch(cSwatch, view); - let spectrum = yield picker.spectrum; + let spectrum = picker.spectrum; let change = spectrum.once("changed"); info("Pressing mouse down over color picker."); diff --git a/devtools/client/inspector/rules/test/browser_rules_colorpicker-revert-on-ESC.js b/devtools/client/inspector/rules/test/browser_rules_colorpicker-revert-on-ESC.js index 66910492cf92..e244d429c97b 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-revert-on-ESC.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-revert-on-ESC.js @@ -35,7 +35,7 @@ function* testPressingEscapeRevertsChanges(view) { is(propEditor.valueSpan.textContent, "#000", "The text of the background-color css property was updated"); - let spectrum = yield cPicker.spectrum; + let spectrum = cPicker.spectrum; info("Pressing ESCAPE to close the tooltip"); let onHidden = cPicker.tooltip.once("hidden"); @@ -76,7 +76,7 @@ function* testPressingEscapeRevertsChangesAndDisables(view) { is(textProp.editor.enable.style.visibility, "hidden", "property enable checkbox is hidden."); - let spectrum = yield cPicker.spectrum; + let spectrum = cPicker.spectrum; info("Pressing ESCAPE to close the tooltip"); let onHidden = cPicker.tooltip.once("hidden"); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-value-after-name_03.js b/devtools/client/inspector/rules/test/browser_rules_edit-value-after-name_03.js index 955748004ed2..246216e1524f 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-value-after-name_03.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-value-after-name_03.js @@ -64,6 +64,6 @@ add_task(function* () { ok(!inplaceEditor(propEditor.valueSpan), "The inplace editor wasn't shown as a result of the color swatch click"); - let spectrum = yield colorPicker.spectrum; + let spectrum = colorPicker.spectrum; is(spectrum.rgb, "200,170,140,0.5", "The correct color picker was shown"); }); diff --git a/devtools/client/inspector/rules/test/browser_rules_eyedropper.js b/devtools/client/inspector/rules/test/browser_rules_eyedropper.js index a135bc9bb251..9a1f5e5bc511 100644 --- a/devtools/client/inspector/rules/test/browser_rules_eyedropper.js +++ b/devtools/client/inspector/rules/test/browser_rules_eyedropper.js @@ -61,7 +61,7 @@ add_task(function* () { let dropper = yield openEyedropper(view, swatch); let tooltip = view.tooltips.colorPicker.tooltip; - ok(tooltip.isHidden(), + ok(!tooltip.isVisible(), "color picker tooltip is closed after opening eyedropper"); yield testESC(swatch, dropper); @@ -134,8 +134,7 @@ function openEyedropper(view, swatch) { let tooltip = view.tooltips.colorPicker.tooltip; tooltip.once("shown", () => { - let tooltipDoc = tooltip.content.contentDocument; - let dropperButton = tooltipDoc.querySelector("#eyedropper-button"); + let dropperButton = tooltip.doc.querySelector("#eyedropper-button"); tooltip.once("eyedropper-opened", (event, dropper) => { deferred.resolve(dropper); diff --git a/devtools/client/inspector/rules/test/browser_rules_filtereditor-appears-on-swatch-click.js b/devtools/client/inspector/rules/test/browser_rules_filtereditor-appears-on-swatch-click.js index d15a84221640..b63e5f1b6af6 100644 --- a/devtools/client/inspector/rules/test/browser_rules_filtereditor-appears-on-swatch-click.js +++ b/devtools/client/inspector/rules/test/browser_rules_filtereditor-appears-on-swatch-click.js @@ -28,6 +28,5 @@ add_task(function* () { ok(!inplaceEditor(swatch.parentNode), "The inplace editor wasn't shown as a result of the filter swatch click"); - yield filterTooltip.widget; yield hideTooltipAndWaitForRuleViewChanged(filterTooltip, view); }); diff --git a/devtools/client/inspector/rules/test/browser_rules_filtereditor-commit-on-ENTER.js b/devtools/client/inspector/rules/test/browser_rules_filtereditor-commit-on-ENTER.js index ef2e4bf4574e..127a2084389b 100644 --- a/devtools/client/inspector/rules/test/browser_rules_filtereditor-commit-on-ENTER.js +++ b/devtools/client/inspector/rules/test/browser_rules_filtereditor-commit-on-ENTER.js @@ -25,7 +25,7 @@ add_task(function* () { info("Get the cssfilter widget instance"); let filterTooltip = view.tooltips.filterEditor; - let widget = yield filterTooltip.widget; + let widget = filterTooltip.widget; info("Set a new value in the cssfilter widget"); onRuleViewChanged = view.once("ruleview-changed"); diff --git a/devtools/client/inspector/rules/test/browser_rules_filtereditor-revert-on-ESC.js b/devtools/client/inspector/rules/test/browser_rules_filtereditor-revert-on-ESC.js index 0d1d6b59da3f..0302f40a9191 100644 --- a/devtools/client/inspector/rules/test/browser_rules_filtereditor-revert-on-ESC.js +++ b/devtools/client/inspector/rules/test/browser_rules_filtereditor-revert-on-ESC.js @@ -38,7 +38,6 @@ function* testPressingEscapeRevertsChanges(view) { function* testPressingEscapeRevertsChangesAndDisables(view) { let ruleEditor = getRuleViewRuleEditor(view, 1); let propEditor = ruleEditor.rule.textProps[0].editor; - let swatch = propEditor.valueSpan.querySelector(".ruleview-filterswatch"); info("Disabling filter property"); let onRuleViewChanged = view.once("ruleview-changed"); @@ -56,6 +55,7 @@ function* testPressingEscapeRevertsChangesAndDisables(view) { let newValue = yield getRulePropertyValue("filter"); is(newValue, "", "filter should have been unset."); + let swatch = propEditor.valueSpan.querySelector(".ruleview-filterswatch"); yield clickOnFilterSwatch(swatch, view); ok(!propEditor.element.classList.contains("ruleview-overridden"), @@ -103,9 +103,8 @@ function* setValueInFilterWidget(value, view) { info("Setting the CSS filter value in the tooltip"); let filterTooltip = view.tooltips.filterEditor; - let widget = yield filterTooltip.widget; let onRuleViewChanged = view.once("ruleview-changed"); - widget.setCssValue(value); + filterTooltip.widget.setCssValue(value); yield onRuleViewChanged; } @@ -113,8 +112,7 @@ function* pressEscapeToCloseTooltip(view) { info("Pressing ESCAPE to close the tooltip"); let filterTooltip = view.tooltips.filterEditor; - let widget = yield filterTooltip.widget; let onRuleViewChanged = view.once("ruleview-changed"); - EventUtils.sendKey("ESCAPE", widget.styleWindow); + EventUtils.sendKey("ESCAPE", filterTooltip.widget.styleWindow); yield onRuleViewChanged; } diff --git a/devtools/client/inspector/rules/test/head.js b/devtools/client/inspector/rules/test/head.js index a9ef4e405c3e..a1aa872f3c66 100644 --- a/devtools/client/inspector/rules/test/head.js +++ b/devtools/client/inspector/rules/test/head.js @@ -358,9 +358,14 @@ function getRuleViewSelectorHighlighterIcon(view, selectorText) { */ var simulateColorPickerChange = Task.async(function* (ruleView, colorPicker, newRgba, expectedChange) { + let onComputedStyleChanged; + if (expectedChange) { + let {selector, name, value} = expectedChange; + onComputedStyleChanged = waitForComputedStyleProperty(selector, null, name, value); + } let onRuleViewChanged = ruleView.once("ruleview-changed"); info("Getting the spectrum colorpicker object"); - let spectrum = yield colorPicker.spectrum; + let spectrum = colorPicker.spectrum; info("Setting the new color"); spectrum.rgb = newRgba; info("Applying the change"); @@ -371,8 +376,7 @@ var simulateColorPickerChange = Task.async(function* (ruleView, colorPicker, if (expectedChange) { info("Waiting for the style to be applied on the page"); - let {selector, name, value} = expectedChange; - yield waitForComputedStyleProperty(selector, null, name, value); + yield onComputedStyleChanged; } }); diff --git a/devtools/client/inspector/shared/style-inspector-overlays.js b/devtools/client/inspector/shared/style-inspector-overlays.js index d1c0a48111bc..42d45777368a 100644 --- a/devtools/client/inspector/shared/style-inspector-overlays.js +++ b/devtools/client/inspector/shared/style-inspector-overlays.js @@ -261,10 +261,10 @@ exports.TooltipsOverlay = TooltipsOverlay; TooltipsOverlay.prototype = { get isEditing() { - return this.colorPicker.tooltip.isShown() || + return this.colorPicker.tooltip.isVisible() || this.colorPicker.eyedropperOpen || - this.cubicBezier.tooltip.isShown() || - this.filterEditor.tooltip.isShown(); + this.cubicBezier.tooltip.isVisible() || + this.filterEditor.tooltip.isVisible(); }, /** @@ -290,11 +290,12 @@ TooltipsOverlay.prototype = { if (this.isRuleView) { // Color picker tooltip - this.colorPicker = new SwatchColorPickerTooltip(panelDoc); + let { toolbox } = this.view.inspector; + this.colorPicker = new SwatchColorPickerTooltip(toolbox); // Cubic bezier tooltip - this.cubicBezier = new SwatchCubicBezierTooltip(panelDoc); + this.cubicBezier = new SwatchCubicBezierTooltip(toolbox); // Filter editor tooltip - this.filterEditor = new SwatchFilterTooltip(panelDoc); + this.filterEditor = new SwatchFilterTooltip(toolbox); } this._isStarted = true; @@ -381,12 +382,12 @@ TooltipsOverlay.prototype = { return false; } - if (this.isRuleView && this.colorPicker.tooltip.isShown()) { + if (this.isRuleView && this.colorPicker.tooltip.isVisible()) { this.colorPicker.revert(); this.colorPicker.hide(); } - if (this.isRuleView && this.cubicBezier.tooltip.isShown()) { + if (this.isRuleView && this.cubicBezier.tooltip.isVisible()) { this.cubicBezier.revert(); this.cubicBezier.hide(); } @@ -395,7 +396,7 @@ TooltipsOverlay.prototype = { this.cssDocs.hide(); } - if (this.isRuleView && this.filterEditor.tooltip.isShown()) { + if (this.isRuleView && this.filterEditor.tooltip.isVisible()) { this.filterEditor.revert(); this.filterEdtior.hide(); } diff --git a/devtools/client/inspector/shared/test/browser.ini b/devtools/client/inspector/shared/test/browser.ini index 253f246df7e7..deb24e00bd54 100644 --- a/devtools/client/inspector/shared/test/browser.ini +++ b/devtools/client/inspector/shared/test/browser.ini @@ -34,7 +34,6 @@ skip-if = e10s # Bug 1111546 (e10s) [browser_styleinspector_tooltip-multiple-background-images.js] [browser_styleinspector_tooltip-shorthand-fontfamily.js] [browser_styleinspector_tooltip-size.js] -skip-if = e10s || os == 'linux' # Bug 1111546 (e10s), bug 1093431 (linux) [browser_styleinspector_transform-highlighter-01.js] [browser_styleinspector_transform-highlighter-02.js] [browser_styleinspector_transform-highlighter-03.js] diff --git a/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-size.js b/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-size.js index 14b50c91677c..c1d4cafd8547 100644 --- a/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-size.js +++ b/devtools/client/inspector/shared/test/browser_styleinspector_tooltip-size.js @@ -70,12 +70,13 @@ function* testPickerDimension(ruleView) { // The colorpicker spectrum's iframe has a fixed width height, so let's // make sure the tooltip is at least as big as that - let w = cPicker.tooltip.panel.querySelector("iframe").width; - let h = cPicker.tooltip.panel.querySelector("iframe").height; - let panelRect = cPicker.tooltip.panel.getBoundingClientRect(); + let spectrumRect = cPicker.spectrum.element.getBoundingClientRect(); + let panelRect = cPicker.tooltip.container.getBoundingClientRect(); - ok(panelRect.width >= w, "The panel is wide enough to show the picker"); - ok(panelRect.height >= h, "The panel is high enough to show the picker"); + ok(panelRect.width >= spectrumRect.width, + "The panel is wide enough to show the picker"); + ok(panelRect.height >= spectrumRect.height, + "The panel is high enough to show the picker"); let onHidden = cPicker.tooltip.once("hidden"); let onRuleViewChanged = ruleView.once("ruleview-changed"); diff --git a/devtools/client/jar.mn b/devtools/client/jar.mn index 47008e71d89c..167bc783b36d 100644 --- a/devtools/client/jar.mn +++ b/devtools/client/jar.mn @@ -127,13 +127,11 @@ devtools.jar: content/framework/connect/connect.css (framework/connect/connect.css) content/framework/connect/connect.js (framework/connect/connect.js) content/shared/widgets/graphs-frame.xhtml (shared/widgets/graphs-frame.xhtml) - content/shared/widgets/spectrum-frame.xhtml (shared/widgets/spectrum-frame.xhtml) - content/shared/widgets/cubic-bezier-frame.xhtml (shared/widgets/cubic-bezier-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-frame.xhtml (shared/widgets/filter-frame.xhtml) content/shared/widgets/filter-widget.css (shared/widgets/filter-widget.css) + content/shared/widgets/spectrum.css (shared/widgets/spectrum.css) content/eyedropper/eyedropper.xul (eyedropper/eyedropper.xul) content/eyedropper/crosshairs.css (eyedropper/crosshairs.css) content/eyedropper/nocursor.css (eyedropper/nocursor.css) @@ -195,7 +193,6 @@ devtools.jar: skin/images/breadcrumbs-scrollbutton.png (themes/images/breadcrumbs-scrollbutton.png) skin/images/breadcrumbs-scrollbutton@2x.png (themes/images/breadcrumbs-scrollbutton@2x.png) skin/animationinspector.css (themes/animationinspector.css) - skin/spectrum.css (themes/spectrum.css) skin/eyedropper.css (themes/eyedropper.css) skin/canvasdebugger.css (themes/canvasdebugger.css) skin/debugger.css (themes/debugger.css) diff --git a/devtools/client/locales/en-US/filterwidget.dtd b/devtools/client/locales/en-US/filterwidget.dtd deleted file mode 100644 index 3a36f97022dd..000000000000 --- a/devtools/client/locales/en-US/filterwidget.dtd +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/devtools/client/locales/en-US/filterwidget.properties b/devtools/client/locales/en-US/filterwidget.properties index acd42d0d2b0f..ddd2f266501c 100644 --- a/devtools/client/locales/en-US/filterwidget.properties +++ b/devtools/client/locales/en-US/filterwidget.properties @@ -37,3 +37,25 @@ dragHandleTooltipText=Drag up or down to re-order filter # filters' labels which can be dragged left/right to increase/decrease # the filter's value (like photoshop) labelDragTooltipText=Drag left or right to decrease or increase the value + +# LOCALIZATION NOTE (filterListSelectPlaceholder): +# This string is used as a preview option in the list of possible filters +# + + + + + + + +
+
+ +
+ `; this.filtersList = this.el.querySelector("#filters"); this.presetsList = this.el.querySelector("#presets"); this.togglePresets = this.el.querySelector("#toggle-presets"); @@ -183,7 +212,7 @@ CSSFilterEditorWidget.prototype = { _populateFilterSelect: function () { let select = this.filterSelect; filterList.forEach(filter => { - let option = this.doc.createElement("option"); + let option = this.doc.createElementNS(XHTML_NS, "option"); option.innerHTML = option.value = filter.name; select.appendChild(option); }); @@ -193,31 +222,31 @@ CSSFilterEditorWidget.prototype = { * Creates a template for filter elements which is cloned and used in render */ _buildFilterItemMarkup: function () { - let base = this.doc.createElement("div"); + let base = this.doc.createElementNS(XHTML_NS, "div"); base.className = "filter"; - let name = this.doc.createElement("div"); + let name = this.doc.createElementNS(XHTML_NS, "div"); name.className = "filter-name"; - let value = this.doc.createElement("div"); + let value = this.doc.createElementNS(XHTML_NS, "div"); value.className = "filter-value"; - let drag = this.doc.createElement("i"); + let drag = this.doc.createElementNS(XHTML_NS, "i"); drag.title = L10N.getStr("dragHandleTooltipText"); - let label = this.doc.createElement("label"); + let label = this.doc.createElementNS(XHTML_NS, "label"); name.appendChild(drag); name.appendChild(label); - let unitPreview = this.doc.createElement("span"); - let input = this.doc.createElement("input"); + let unitPreview = this.doc.createElementNS(XHTML_NS, "span"); + let input = this.doc.createElementNS(XHTML_NS, "input"); input.classList.add("devtools-textinput"); value.appendChild(input); value.appendChild(unitPreview); - let removeButton = this.doc.createElement("button"); + let removeButton = this.doc.createElementNS(XHTML_NS, "button"); removeButton.className = "remove-button"; base.appendChild(name); @@ -228,16 +257,16 @@ CSSFilterEditorWidget.prototype = { }, _buildPresetItemMarkup: function () { - let base = this.doc.createElement("div"); + let base = this.doc.createElementNS(XHTML_NS, "div"); base.classList.add("preset"); - let name = this.doc.createElement("label"); + let name = this.doc.createElementNS(XHTML_NS, "label"); base.appendChild(name); - let value = this.doc.createElement("span"); + let value = this.doc.createElementNS(XHTML_NS, "span"); base.appendChild(value); - let removeButton = this.doc.createElement("button"); + let removeButton = this.doc.createElementNS(XHTML_NS, "button"); removeButton.classList.add("remove-button"); base.appendChild(removeButton); @@ -659,6 +688,11 @@ CSSFilterEditorWidget.prototype = { renderPresets: function () { this.getPresets().then(presets => { + // getPresets is async and the widget may be destroyed in between. + if (!this.presetsList) { + return; + } + if (!presets || !presets.length) { this.presetsList.innerHTML = `

${L10N.getStr("emptyPresetList")}

`; this.emit("render"); diff --git a/devtools/client/shared/widgets/Spectrum.js b/devtools/client/shared/widgets/Spectrum.js index da746ffb6a78..00110f13e649 100644 --- a/devtools/client/shared/widgets/Spectrum.js +++ b/devtools/client/shared/widgets/Spectrum.js @@ -5,6 +5,7 @@ "use strict"; const EventEmitter = require("devtools/shared/event-emitter"); +const XHTML_NS = "http://www.w3.org/1999/xhtml"; /** * Spectrum creates a color picker widget in any container you give it. @@ -32,7 +33,7 @@ const EventEmitter = require("devtools/shared/event-emitter"); function Spectrum(parentEl, rgb) { EventEmitter.decorate(this); - this.element = parentEl.ownerDocument.createElement("div"); + this.element = parentEl.ownerDocument.createElementNS(XHTML_NS, "div"); this.parentEl = parentEl; this.element.className = "spectrum-container"; @@ -131,21 +132,6 @@ Spectrum.rgbToHsv = function (r, g, b, a) { return [h, s, v, a]; }; -Spectrum.getOffset = function (el) { - let curleft = 0, curtop = 0; - if (el.offsetParent) { - while (el) { - curleft += el.offsetLeft; - curtop += el.offsetTop; - el = el.offsetParent; - } - } - return { - left: curleft, - top: curtop - }; -}; - Spectrum.draggable = function (element, onmove, onstart, onstop) { onmove = onmove || function () {}; onstart = onstart || function () {}; @@ -188,7 +174,7 @@ Spectrum.draggable = function (element, onmove, onstart, onstop) { maxHeight = element.offsetHeight; maxWidth = element.offsetWidth; - offset = Spectrum.getOffset(element); + offset = element.getBoundingClientRect(); move(e); diff --git a/devtools/client/shared/widgets/Tooltip.js b/devtools/client/shared/widgets/Tooltip.js index 58bde20c02e2..4d7a77a7e8a5 100644 --- a/devtools/client/shared/widgets/Tooltip.js +++ b/devtools/client/shared/widgets/Tooltip.js @@ -19,6 +19,8 @@ const {Eyedropper} = require("devtools/client/eyedropper/eyedropper"); const {gDevTools} = require("devtools/client/framework/devtools"); const Services = require("Services"); const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm"); +const {HTMLTooltip} = require("devtools/client/shared/widgets/HTMLTooltip"); +const {KeyShortcuts} = require("devtools/client/shared/key-shortcuts"); loader.lazyRequireGetter(this, "beautify", "devtools/shared/jsbeautify/beautify"); loader.lazyRequireGetter(this, "setNamedTimeout", "devtools/client/shared/widgets/view-helpers", true); @@ -31,11 +33,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "VariablesViewController", "resource://devtools/client/shared/widgets/VariablesViewController.jsm"); const XHTML_NS = "http://www.w3.org/1999/xhtml"; -const SPECTRUM_FRAME = "chrome://devtools/content/shared/widgets/spectrum-frame.xhtml"; -const CUBIC_BEZIER_FRAME = - "chrome://devtools/content/shared/widgets/cubic-bezier-frame.xhtml"; const MDN_DOCS_FRAME = "chrome://devtools/content/shared/widgets/mdn-docs-frame.xhtml"; -const FILTER_FRAME = "chrome://devtools/content/shared/widgets/filter-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"]; @@ -557,99 +555,6 @@ Tooltip.prototype = { return def.promise; }, - /** - * Fill the tooltip with a new instance of the spectrum color picker widget - * initialized with the given color, and return a promise that resolves to - * the instance of spectrum - */ - setColorPickerContent: function (color) { - let dimensions = {width: "210", height: "216"}; - let panel = this.panel; - return this.setIFrameContent(dimensions, SPECTRUM_FRAME).then(onLoaded); - - function onLoaded(iframe) { - let win = iframe.contentWindow.wrappedJSObject; - let def = defer(); - let container = win.document.getElementById("spectrum"); - let spectrum = new Spectrum(container, color); - - function finalizeSpectrum() { - spectrum.show(); - def.resolve(spectrum); - } - - // Finalize spectrum's init when the tooltip becomes visible - if (panel.state == "open") { - finalizeSpectrum(); - } else { - panel.addEventListener("popupshown", function shown() { - panel.removeEventListener("popupshown", shown, true); - finalizeSpectrum(); - }, true); - } - return def.promise; - } - }, - - /** - * Fill the tooltip with a new instance of the cubic-bezier widget - * initialized with the given value, and return a promise that resolves to - * the instance of the widget - */ - setCubicBezierContent: function (bezier) { - let dimensions = {width: "500", height: "360"}; - let panel = this.panel; - return this.setIFrameContent(dimensions, CUBIC_BEZIER_FRAME).then(onLoaded); - - function onLoaded(iframe) { - let win = iframe.contentWindow.wrappedJSObject; - let def = defer(); - let container = win.document.getElementById("container"); - let widget = new CubicBezierWidget(container, bezier); - - // Resolve to the widget instance whenever the popup becomes visible - if (panel.state == "open") { - def.resolve(widget); - } else { - panel.addEventListener("popupshown", function shown() { - panel.removeEventListener("popupshown", shown, true); - def.resolve(widget); - }, true); - } - return def.promise; - } - }, - - /** - * Fill the tooltip with a new instance of the CSSFilterEditorWidget - * widget initialized with the given filter value, and return a promise - * that resolves to the instance of the widget when ready. - */ - setFilterContent: function (filter) { - let dimensions = {width: "500", height: "200"}; - let panel = this.panel; - - return this.setIFrameContent(dimensions, FILTER_FRAME).then(onLoaded); - - function onLoaded(iframe) { - let win = iframe.contentWindow.wrappedJSObject; - let def = defer(); - let container = win.document.getElementById("container"); - let widget = new CSSFilterEditorWidget(container, filter); - - // Resolve to the widget instance whenever the popup becomes visible - if (panel.state === "open") { - def.resolve(widget); - } else { - panel.addEventListener("popupshown", function shown() { - panel.removeEventListener("popupshown", shown, true); - def.resolve(widget); - }, true); - } - return def.promise; - } - }, - /** * Set the content of this tooltip to the MDN docs widget. * @@ -681,29 +586,44 @@ Tooltip.prototype = { * Base class for all (color, gradient, ...)-swatch based value editors inside * tooltips * - * @param {XULDocument} doc + * @param {Toolbox} toolbox + * The devtools toolbox, needed to get the devtools main window. */ -function SwatchBasedEditorTooltip(doc) { +function SwatchBasedEditorTooltip(toolbox, stylesheet) { // 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 and - this.tooltip = new Tooltip(doc, { - consumeOutsideClick: true, - closeOnKeys: [ESCAPE_KEYCODE, RETURN_KEYCODE], - noAutoFocus: false + this.tooltip = new HTMLTooltip(toolbox, { + type: "arrow", + consumeOutsideClicks: true, + useXulWrapper: true, + stylesheet }); // By default, swatch-based editor tooltips revert value change on and // commit value change on - this._onTooltipKeypress = (event, code) => { - if (code === ESCAPE_KEYCODE) { - this.revert(); - } else if (code === RETURN_KEYCODE) { - this.commit(); + this.shortcuts = new KeyShortcuts({ + window: this.tooltip.topWindow + }); + this.shortcuts.on("Escape", (name, event) => { + if (!this.tooltip.isVisible()) { + return; } - }; - this.tooltip.on("keypress", this._onTooltipKeypress); + this.revert(); + this.hide(); + event.stopPropagation(); + event.preventDefault(); + }); + this.shortcuts.on("Return", (name, event) => { + if (!this.tooltip.isVisible()) { + return; + } + this.commit(); + this.hide(); + event.stopPropagation(); + event.preventDefault(); + }); // All target swatches are kept in a map, indexed by swatch DOM elements this.swatches = new Map(); @@ -722,18 +642,14 @@ SwatchBasedEditorTooltip.prototype = { this.tooltip.show(this.activeSwatch, "topcenter bottomleft"); // When the tooltip is closed by clicking outside the panel we want to - // commit any changes. Because the "hidden" event destroys the tooltip we - // need to do this before the tooltip is destroyed (in the "hiding" - // event). - this.tooltip.once("hiding", () => { + // commit any changes. + this.tooltip.once("hidden", () => { if (!this._reverted && !this.eyedropperOpen) { this.commit(); } this._reverted = false; - }); - // Once the tooltip is hidden we need to clean up any remaining objects. - this.tooltip.once("hidden", () => { + // Once the tooltip is hidden we need to clean up any remaining objects. if (!this.eyedropperOpen) { this.activeSwatch = null; } @@ -825,7 +741,7 @@ SwatchBasedEditorTooltip.prototype = { if (this.activeSwatch) { this._reverted = true; let swatch = this.swatches.get(this.activeSwatch); - this.tooltip.once("hiding", () => { + this.tooltip.once("hidden", () => { swatch.callbacks.onRevert(); }); } @@ -846,6 +762,7 @@ SwatchBasedEditorTooltip.prototype = { this.activeSwatch = null; this.tooltip.off("keypress", this._onTooltipKeypress); this.tooltip.destroy(); + this.shortcuts.destroy(); } }; @@ -856,14 +773,16 @@ SwatchBasedEditorTooltip.prototype = { * It just wraps a standard Tooltip and sets its content with an instance of a * color picker. * - * @param {XULDocument} doc + * @param {Toolbox} toolbox + * The devtools toolbox, needed to get the devtools main window. */ -function SwatchColorPickerTooltip(doc) { - SwatchBasedEditorTooltip.call(this, doc); +function SwatchColorPickerTooltip(toolbox) { + let stylesheet = "chrome://devtools/content/shared/widgets/spectrum.css"; + SwatchBasedEditorTooltip.call(this, toolbox, stylesheet); // Creating a spectrum instance. this.spectrum will always be a promise that // resolves to the spectrum instance - this.spectrum = this.tooltip.setColorPickerContent([0, 0, 0, 1]); + this.spectrum = this.setColorPickerContent([0, 0, 0, 1]); this._onSpectrumColorChange = this._onSpectrumColorChange.bind(this); this._openEyeDropper = this._openEyeDropper.bind(this); } @@ -872,6 +791,36 @@ module.exports.SwatchColorPickerTooltip = SwatchColorPickerTooltip; SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.prototype, { + /** + * Fill the tooltip with a new instance of the spectrum color picker widget + * initialized with the given color, and return the instance of spectrum + */ + setColorPickerContent: function (color) { + let { doc } = this.tooltip; + + 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 eyedropper = doc.createElementNS(XHTML_NS, "button"); + eyedropper.id = "eyedropper-button"; + eyedropper.className = "devtools-button"; + container.appendChild(eyedropper); + + this.tooltip.setContent(container, { width: 210, height: 216 }); + + let spectrum = new Spectrum(spectrumNode, color); + + // Wait for the tooltip to be shown before calling spectrum.show + // as it expect to be visible in order to compute DOM element sizes. + this.tooltip.once("shown", () => { + spectrum.show(); + }); + + return spectrum; + }, + /** * Overriding the SwatchBasedEditorTooltip.show function to set spectrum's * color. @@ -884,16 +833,13 @@ Heritage.extend(SwatchBasedEditorTooltip.prototype, { this.currentSwatchColor = this.activeSwatch.nextSibling; this._originalColor = this.currentSwatchColor.textContent; let color = this.activeSwatch.style.backgroundColor; - this.spectrum.then(spectrum => { - spectrum.off("changed", this._onSpectrumColorChange); - spectrum.rgb = this._colorToRgba(color); - spectrum.on("changed", this._onSpectrumColorChange); - spectrum.updateUI(); - }); + this.spectrum.off("changed", this._onSpectrumColorChange); + this.spectrum.rgb = this._colorToRgba(color); + this.spectrum.on("changed", this._onSpectrumColorChange); + this.spectrum.updateUI(); } - let tooltipDoc = this.tooltip.content.contentDocument; - let eyeButton = tooltipDoc.querySelector("#eyedropper-button"); + let eyeButton = this.tooltip.doc.querySelector("#eyedropper-button"); eyeButton.addEventListener("click", this._openEyeDropper); }, @@ -967,10 +913,8 @@ Heritage.extend(SwatchBasedEditorTooltip.prototype, { destroy: function () { SwatchBasedEditorTooltip.prototype.destroy.call(this); this.currentSwatchColor = null; - this.spectrum.then(spectrum => { - spectrum.off("changed", this._onSpectrumColorChange); - spectrum.destroy(); - }); + this.spectrum.off("changed", this._onSpectrumColorChange); + this.spectrum.destroy(); } }); @@ -981,14 +925,16 @@ Heritage.extend(SwatchBasedEditorTooltip.prototype, { * It just wraps a standard Tooltip and sets its content with an instance of a * CubicBezierWidget. * - * @param {XULDocument} doc + * @param {Toolbox} toolbox + * The devtools toolbox, needed to get the devtools main window. */ -function SwatchCubicBezierTooltip(doc) { - SwatchBasedEditorTooltip.call(this, doc); +function SwatchCubicBezierTooltip(toolbox) { + let stylesheet = "chrome://devtools/content/shared/widgets/cubic-bezier.css"; + SwatchBasedEditorTooltip.call(this, toolbox, stylesheet); // Creating a cubic-bezier instance. // this.widget will always be a promise that resolves to the widget instance - this.widget = this.tooltip.setCubicBezierContent([0, 0, 1, 1]); + this.widget = this.setCubicBezierContent([0, 0, 1, 1]); this._onUpdate = this._onUpdate.bind(this); } @@ -996,6 +942,31 @@ module.exports.SwatchCubicBezierTooltip = SwatchCubicBezierTooltip; SwatchCubicBezierTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.prototype, { + /** + * Fill the tooltip with a new instance of the cubic-bezier widget + * initialized with the given value, and return a promise that resolves to + * the instance of the widget + */ + setCubicBezierContent: function (bezier) { + let { doc } = this.tooltip; + + let container = doc.createElementNS(XHTML_NS, "div"); + container.className = "cubic-bezier-container"; + + this.tooltip.setContent(container, { width: 510, height: 370 }); + + let def = defer(); + + // Wait for the tooltip to be shown before calling instanciating the widget + // as it expect its DOM elements to be visible. + this.tooltip.once("shown", () => { + let widget = new CubicBezierWidget(container, bezier); + def.resolve(widget); + }); + + return def.promise; + }, + /** * Overriding the SwatchBasedEditorTooltip.show function to set the cubic * bezier curve in the widget @@ -1079,14 +1050,15 @@ CssDocsTooltip.prototype = { * It just wraps a standard Tooltip and sets its content with an instance of a * CSSFilterEditorWidget. * - * @param {XULDocument} doc + * @param {Toolbox} toolbox + * The devtools toolbox, needed to get the devtools main window. */ -function SwatchFilterTooltip(doc) { - SwatchBasedEditorTooltip.call(this, doc); +function SwatchFilterTooltip(toolbox) { + let stylesheet = "chrome://devtools/content/shared/widgets/filter-widget.css"; + SwatchBasedEditorTooltip.call(this, toolbox, stylesheet); // Creating a filter editor instance. - // this.widget will always be a promise that resolves to the widget instance - this.widget = this.tooltip.setFilterContent("none"); + this.widget = this.setFilterContent("none"); this._onUpdate = this._onUpdate.bind(this); } @@ -1094,18 +1066,32 @@ exports.SwatchFilterTooltip = SwatchFilterTooltip; SwatchFilterTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.prototype, { + /** + * Fill the tooltip with a new instance of the CSSFilterEditorWidget + * widget initialized with the given filter value, and return a promise + * that resolves to the instance of the widget when ready. + */ + setFilterContent: function (filter) { + let { doc } = this.tooltip; + + let container = doc.createElementNS(XHTML_NS, "div"); + container.id = "filter-container"; + + this.tooltip.setContent(container, { width: 510, height: 200 }); + + return new CSSFilterEditorWidget(container, filter); + }, + show: function () { // Call the parent class' show function SwatchBasedEditorTooltip.prototype.show.call(this); // Then set the filter value and listen to changes to preview them if (this.activeSwatch) { this.currentFilterValue = this.activeSwatch.nextSibling; - this.widget.then(widget => { - widget.off("updated", this._onUpdate); - widget.on("updated", this._onUpdate); - widget.setCssValue(this.currentFilterValue.textContent); - widget.render(); - }); + this.widget.off("updated", this._onUpdate); + this.widget.on("updated", this._onUpdate); + this.widget.setCssValue(this.currentFilterValue.textContent); + this.widget.render(); } }, @@ -1128,10 +1114,8 @@ Heritage.extend(SwatchBasedEditorTooltip.prototype, { destroy: function () { SwatchBasedEditorTooltip.prototype.destroy.call(this); this.currentFilterValue = null; - this.widget.then(widget => { - widget.off("updated", this._onUpdate); - widget.destroy(); - }); + this.widget.off("updated", this._onUpdate); + this.widget.destroy(); }, /** diff --git a/devtools/client/shared/widgets/cubic-bezier-frame.xhtml b/devtools/client/shared/widgets/cubic-bezier-frame.xhtml deleted file mode 100644 index 73b6e309976e..000000000000 --- a/devtools/client/shared/widgets/cubic-bezier-frame.xhtml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - -
-
-
- -
- -
-
- -
-
- - - diff --git a/devtools/client/shared/widgets/filter-widget.css b/devtools/client/shared/widgets/filter-widget.css index 6d7624f661ac..9be6425fdaae 100644 --- a/devtools/client/shared/widgets/filter-widget.css +++ b/devtools/client/shared/widgets/filter-widget.css @@ -2,23 +2,18 @@ * 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/. */ -html, body { - height: 100%; - margin: 0; - overflow: hidden; - font: message-box; - color: var(--theme-body-color); -} - /* Main container: Displays the filters and presets in 2 columns */ -#container { +#filter-container { height: 100%; display: flex; position: relative; + padding: 5px; + /* when opened in a xul:panel, a gray color is applied to text */ + color: var(--theme-body-color); } -#container.dragging { +#filter-container.dragging { -moz-user-select: none; } @@ -49,13 +44,13 @@ html, body { margin-top: 4px; } -#container:not(.show-presets) .presets-list { +#filter-container:not(.show-presets) .presets-list { width: 0; border-left: none; padding-left: 0; } -#container.show-presets .filters-list { +#filter-container.show-presets .filters-list { width: 300px; } @@ -211,14 +206,14 @@ input { display: none !important; } -#container .dragging { +#filter-container .dragging { position: relative; z-index: 10; cursor: grab; } /* message shown when there's no filter specified */ -#container p { +#filter-container p { text-align: center; line-height: 20px; } diff --git a/devtools/client/shared/widgets/spectrum-frame.xhtml b/devtools/client/shared/widgets/spectrum-frame.xhtml deleted file mode 100644 index 1b33a098efa7..000000000000 --- a/devtools/client/shared/widgets/spectrum-frame.xhtml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - -