Bug 1332086 - Rearrange the existing color picker to the new design. r?gl draft
authorMicah Tigley <tigleym@gmail.com>
Tue, 22 Aug 2017 22:55:38 -0600
changeset 651042 2f8d606fbb9ad265890ef327ed0dabeacf74c5a6
parent 650961 fa27d49fed598d42449658ae05005d55a0a23e4d
child 727554 6ed11fc230ef30477ebe2f0ddd028ae4c6052775
push id75557
push userbmo:tigleym@gmail.com
push dateWed, 23 Aug 2017 04:56:18 +0000
reviewersgl
bugs1332086
milestone57.0a1
Bug 1332086 - Rearrange the existing color picker to the new design. r?gl MozReview-Commit-ID: 3bvHOGjmTGd
devtools/client/shared/widgets/ColorWidget.js
devtools/client/shared/widgets/color-widget.css
devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js
--- a/devtools/client/shared/widgets/ColorWidget.js
+++ b/devtools/client/shared/widgets/ColorWidget.js
@@ -46,19 +46,19 @@ function ColorWidget(parentEl, rgb) {
 
   this.parentEl = parentEl;
 
   this.onAlphaSliderMove = this.onAlphaSliderMove.bind(this);
   this.onElementClick = this.onElementClick.bind(this);
   this.onDraggerMove = this.onDraggerMove.bind(this);
   this.onHexInputChange = this.onHexInputChange.bind(this);
   this.onHslaInputChange = this.onHslaInputChange.bind(this);
+  this.onHueSliderMove = this.onHueSliderMove.bind(this);
   this.onRgbaInputChange = this.onRgbaInputChange.bind(this);
   this.onSelectValueChange = this.onSelectValueChange.bind(this);
-  this.onSliderMove = this.onSliderMove.bind(this);
   this.updateContrast = this.updateContrast.bind(this);
 
   this.initializeColorWidget();
 
   if (rgb) {
     this.rgb = rgb;
     this.updateUI();
   }
@@ -262,116 +262,134 @@ ColorWidget.prototype = {
   initializeColorWidget: function () {
     let colorNameLabel = L10N.getStr("inspector.colorwidget.colorNameLabel");
     this.parentEl.innerHTML = "";
     this.element = this.parentEl.ownerDocument.createElementNS(XHTML_NS, "div");
 
     this.element.className = "colorwidget-container";
     // eslint-disable-next-line no-unsanitized/property
     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 class="colorwidget-flex-container">
+        <div class="colorwidget-color-picker">
+          <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>
+          </div>
+          <div class="colorwidget-bottom">
+            <div class="colorwidget-color-preview"></div>
+            <button id="eyedropper-button" class="devtools-button"></button>
+            <div class="colorwidget-slider-container">
+              <div class="colorwidget-hue colorwidget-box colorwidget-box">
+                <div class="colorwidget-hue-inner">
+                  <div class="colorwidget-hue-handle colorwidget-slider-control"></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>
           </div>
-          <div class="colorwidget-hue colorwidget-box">
-            <div class="colorwidget-slider colorwidget-slider-control"></div>
+        </div>
+        <div class="colorwidget-color-editor">
+          <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>
+          <div class="colorwidget-colorname">
+            <label class="colorwidget-colorname-label">${colorNameLabel}</label>
+            <div class="colorwidget-colorname-value"></div>
+          </div>
+          <div class="colorwidget-contrast">
+            <div class="colorwidget-contrast-info"></div>
+            <div class="colorwidget-contrast-inner">
+              <span class="colorwidget-colorswatch"></span>
+              <span class="colorwidget-contrast-ratio"></span>
+              <span class="colorwidget-contrast-grade"></span>
+              <button class="colorwidget-contrast-help devtools-button"></button>
+            </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>
-      <div class="colorwidget-colorname">
-        <label class="colorwidget-colorname-label">${colorNameLabel}</label>
-        <span class="colorwidget-colorname-value"></span>
-      </div>
-    <div class="colorwidget-contrast">
-      <div class="colorwidget-contrast-info"></div>
-      <div class="colorwidget-contrast-inner">
-        <span class="colorwidget-colorswatch"></span>
-        <span class="colorwidget-contrast-ratio"></span>
-        <span class="colorwidget-contrast-grade"></span>
-        <button class="colorwidget-contrast-help devtools-button"></button>
-      </div>
-    </div>
     `;
 
     this.element.addEventListener("click", this.onElementClick);
 
     this.parentEl.appendChild(this.element);
 
     this.closestBackgroundColor = "rgba(255, 255, 255, 1)";
 
     this.colorName = this.element.querySelector(".colorwidget-colorname-value");
 
     this.contrast = this.element.querySelector(".colorwidget-contrast");
     this.contrastInfo = this.element.querySelector(".colorwidget-contrast-info");
     this.contrastInfo.textContent = L10N.getStr(
       "inspector.colorwidget.contrastRatio.header"
-    );
+    ) + ":";
 
     this.contrastInner = this.element.querySelector(".colorwidget-contrast-inner");
     this.contrastSwatch = this.contrastInner.querySelector(".colorwidget-colorswatch");
 
     this.contrastSwatch.textContent = SAMPLE_TEXT;
 
     this.contrastRatio = this.contrastInner.querySelector(".colorwidget-contrast-ratio");
     this.contrastGrade = this.contrastInner.querySelector(".colorwidget-contrast-grade");
     this.contrastHelp = this.contrastInner.querySelector(".colorwidget-contrast-help");
 
-    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.hueSlider = this.element.querySelector(".colorwidget-hue");
+    this.hueSliderInner = this.element.querySelector(".colorwidget-hue-inner");
+    this.hueSliderHelper = this.element.querySelector(".colorwidget-hue-handle");
+    ColorWidget.draggable(this.hueSliderInner, this.onHueSliderMove.bind(this));
+
+    this.colorPreview = this.element.querySelector(".colorwidget-color-preview");
+
     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);
@@ -385,40 +403,40 @@ ColorWidget.prototype = {
     };
     this.hslaValue.addEventListener("input", this.onHslaInputChange);
   },
 
   show: Task.async(function* () {
     this.initializeColorWidget();
     this.element.classList.add("colorwidget-show");
 
-    this.slideHeight = this.slider.offsetHeight;
     this.dragWidth = this.dragger.offsetWidth;
     this.dragHeight = this.dragger.offsetHeight;
     this.dragHelperHeight = this.dragHelper.offsetHeight;
-    this.slideHelperHeight = this.slideHelper.offsetHeight;
     this.alphaSliderWidth = this.alphaSliderInner.offsetWidth;
     this.alphaSliderHelperWidth = this.alphaSliderHelper.offsetWidth;
 
+    this.hueSliderWidth = this.hueSliderInner.offsetWidth;
+    this.hueSliderHelperWidth = this.hueSliderHelper.offsetWidth;
+
     if (this.inspector && this.inspector.selection.nodeFront && this.contrastEnabled) {
       let node = this.inspector.selection.nodeFront;
       this.closestBackgroundColor = yield node.getClosestBackgroundColor();
     }
     this.updateContrast();
 
     this.updateUI();
   }),
 
   onElementClick: function (e) {
     e.stopPropagation();
   },
 
-  onSliderMove: function (dragX, dragY) {
-    this.hsv[0] = (dragY / this.slideHeight);
-    this.hsl[0] = (dragY / this.slideHeight) * 360;
+  onHueSliderMove: function (dragX, dragY) {
+    this.hsv[0] = (dragX / this.hueSliderWidth);
     this.updateUI();
     this.onChange();
   },
 
   onDraggerMove: function (dragX, dragY) {
     this.hsv[1] = dragX / this.dragWidth;
     this.hsv[2] = (this.dragHeight - dragY) / this.dragHeight;
 
@@ -618,18 +636,18 @@ ColorWidget.prototype = {
       -helperDim,
       Math.min(this.dragHeight - helperDim, dragY - helperDim)
     );
 
     this.dragHelper.style.top = dragY + "px";
     this.dragHelper.style.left = dragX + "px";
 
     // Placing the hue slider
-    let slideY = (h * this.slideHeight) - this.slideHelperHeight / 2;
-    this.slideHelper.style.top = slideY + "px";
+    let hueSliderX = (h * this.hueSliderWidth) - (this.hueSliderHelperWidth / 2);
+    this.hueSliderHelper.style.left = hueSliderX + "px";
 
     // Placing the alpha slider
     let alphaSliderX = (this.hsv[3] * this.alphaSliderWidth) -
       (this.alphaSliderHelperWidth / 2);
     this.alphaSliderHelper.style.left = alphaSliderX + "px";
 
     const color = new colorUtils.CssColor(this.rgbCssString);
 
@@ -655,32 +673,34 @@ ColorWidget.prototype = {
 
     let rgb = this.rgb;
     let rgbNoSatVal = this.rgbNoSatVal;
 
     let flatColor = "rgb(" + rgbNoSatVal[0] + ", " + rgbNoSatVal[1] + ", " +
       rgbNoSatVal[2] + ")";
 
     this.dragger.style.backgroundColor = flatColor;
+    this.colorPreview.style.backgroundColor = this.rgbCssString;
 
     let rgbNoAlpha = "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")";
     let rgbAlpha0 = "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ", 0)";
     let alphaGradient = "linear-gradient(to right, " + rgbAlpha0 + ", " +
       rgbNoAlpha + ")";
     this.alphaSliderInner.style.background = alphaGradient;
 
     let colorName = colorUtils.rgbToColorName(rgb[0], rgb[1], rgb[2]);
     this.colorName.textContent = colorName || "---";
   },
 
   destroy: function () {
     this.element.removeEventListener("click", this.onElementClick);
 
     this.parentEl.removeChild(this.element);
 
-    this.slider = null;
+    this.colorPreview = null;
     this.dragger = null;
     this.alphaSlider = this.alphaSliderInner = this.alphaSliderHelper = null;
+    this.hueSlider = this.hueInnerSlider = this.hueSliderHelper = null;
     this.parentEl = null;
     this.element = null;
     this.colorName = null;
   }
 };
--- a/devtools/client/shared/widgets/color-widget.css
+++ b/devtools/client/shared/widgets/color-widget.css
@@ -48,20 +48,38 @@
 }
 
 .colorwidget-container {
   position: relative;
   display: none;
   top: 0;
   left: 0;
   border-radius: 0;
-  width: 200px;
+  width: 100%;
+  height: 200x;
   padding: 5px;
 }
 
+.colorwidget-flex-container {
+  display: flex;
+  flex-direction: row;
+}
+
+.colorwidget-color-picker {
+  width: 50%;
+  padding: 5px;
+}
+
+.colorwidget-color-editor {
+  width: 50%;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-around;
+}
+
 .colorwidget-show {
   display: inline-block;
 }
 
 /* Keep aspect ratio:
 http://www.briangrinstead.com/blog/keep-aspect-ratio-with-html-and-css */
 .colorwidget-top {
   position: relative;
@@ -72,38 +90,56 @@ http://www.briangrinstead.com/blog/keep-
 .colorwidget-top-inner {
   position: absolute;
   top:0;
   left:0;
   bottom:0;
   right:0;
 }
 
+.colorwidget-colorname {
+  padding: 5px;
+}
+
+.colorwidget-colorname-value {
+  font-family: Courier New, Courier, monospace;
+  font-size: 11px;
+  margin-left: 8px;
+  margin-top: 3px;
+}
+
+
 .colorwidget-contrast {
   color: var(--theme-content-color1);
-  padding-top: 4px;
+  padding: 5px;
+}
+
+.colorwidget-contrast-info, .colorwidget-colorname {
+  font-size: 13px;
 }
 
 .colorwidget-colorswatch, .colorwidget-contrast-ratio, .colorwidget-contrast-grade, .colorwidget-contrast-help {
   display: inline-block;
 }
 
 .colorwidget-colorswatch {
-  width: 28%;
+  width: 15%;
+  font-size: 11px;
 }
 
 .colorwidget-contrast-ratio {
   font-family: Courier New, Courier, monospace;
   padding-left: 8px;
-  width: 26%;
+  font-size: 11px;
 }
 
 .colorwidget-contrast-grade {
   font-family: Courier New, Courier, monospace;
   width: 18%;
+  font-size: 11px;
 }
 
 .colorwidget-contrast-help {
   margin-inline-start: 5px;
 }
 
 .colorwidget-contrast-help::before {
   background-image: url(chrome://devtools/skin/images/help.svg);
@@ -115,140 +151,151 @@ http://www.briangrinstead.com/blog/keep-
 }
 
 .colorwidget-color {
   position: absolute;
   top: 0;
   left: 0;
   bottom: 0;
   right: 20%;
-}
-
-.colorwidget-hue {
-  position: absolute;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 83%;
+  width: 100%;
 }
 
 .colorwidget-fill {
   /* Same as colorwidget-color width */
   margin-top: 85%;
 }
 
 .colorwidget-sat, .colorwidget-val {
   position: absolute;
   top: 0;
   left: 0;
   right: 0;
   bottom: 0;
 }
 
-.colorwidget-dragger, .colorwidget-slider {
+.colorwidget-dragger, {
   -moz-user-select: none;
 }
 
-.colorwidget-alpha {
+.colorwidget-alpha,
+.colorwidget-hue {
   position: relative;
   height: 8px;
   margin-top: 3px;
 }
 
-.colorwidget-alpha-inner {
+.colorwidget-alpha-inner,
+.colorwidget-hue-inner {
   height: 100%;
 }
 
-.colorwidget-alpha-handle {
+.colorwidget-alpha-handle,
+.colorwidget-hue-handle {
   position: absolute;
   top: -3px;
   bottom: -3px;
   width: 5px;
   left: 50%;
 }
 
 .colorwidget-sat {
   background-image: linear-gradient(to right, #FFF, rgba(204, 154, 129, 0));
 }
 
 .colorwidget-val {
   background-image: linear-gradient(to top, #000000, rgba(204, 154, 129, 0));
 }
 
 .colorwidget-hue {
-  background: linear-gradient(to bottom, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
+  background: linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
 }
 
 .colorwidget-dragger {
   position: absolute;
   top: 0px;
   left: 0px;
   cursor: pointer;
   border-radius: 50%;
   height: 8px;
   width: 8px;
   border: 1px solid white;
   box-shadow: 0 0 2px rgba(0,0,0,.6);
 }
 
-.colorwidget-slider {
-  position: absolute;
-  top: 0;
-  height: 5px;
-  left: -3px;
-  right: -3px;
+.colorwidget-bottom {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  margin-top: 3px;
+  width: 100%;
+}
+
+.colorwidget-slider-container {
+  display: flex;
+  flex-direction: column;
+  width: 70%;
+}
+
+.colorwidget-color-preview {
+  border-radius: 50%;
+  width: 25px;
+  height: 22px;
 }
 
 /**
  * Color Widget Editor
  */
 
 .colorwidget-value {
   position: relative;
   margin-top: 8px;
+  padding: 5px;
 }
 
 /**
  * Color Widget Select
  */
 
 .colorwidget-select {
-  width: 100%;
+  width: 95%;
 }
 
 .colorwidget-select-spacing {
-  letter-spacing: 40px;
+  letter-spacing: inherit;
 }
 
 .colorwidget-select-spacing option {
-  letter-spacing: initial;
+  letter-spacing: inherit;
 }
 
 /**
  * Color Widget Inputs
  */
 
 .colorwidget-hidden {
   display: none;
 }
 
 .colorwidget-hex,
 .colorwidget-rgba,
 .colorwidget-hsla {
-  width: 200px;
+  width: 95%;
   font-size: 0;
 }
 
 .colorwidget-hex-input {
-  width: 192px;
+  width: 90%;
+  margin: 1px;
 }
 
 .colorwidget-rgba-r,
 .colorwidget-rgba-g,
 .colorwidget-rgba-b,
 .colorwidget-rgba-a,
 .colorwidget-hsla-h,
 .colorwidget-hsla-s,
 .colorwidget-hsla-l,
 .colorwidget-hsla-a {
-  width: 42px;
-  margin: 0;
-}
\ No newline at end of file
+  width: 15%;
+  margin: 1px;
+  font-size: 11px;
+}
--- a/devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js
+++ b/devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js
@@ -63,34 +63,33 @@ SwatchColorPickerTooltip.prototype = Her
 
     let widget;
     let node = doc.createElementNS(XHTML_NS, "div");
 
     if (NEW_COLOR_WIDGET) {
       node.id = "colorwidget";
       container.appendChild(node);
       widget = new ColorWidget(node, color);
-      this.tooltip.setContent(container, { width: 218, height: 320 });
+      this.tooltip.setContent(container, { width: 300, height: 180 });
     } else {
       node.id = "spectrum";
       container.appendChild(node);
       widget = new Spectrum(node, color);
       this.tooltip.setContent(container, { width: 218, height: 224 });
+      let eyedropper = doc.createElementNS(XHTML_NS, "button");
+      eyedropper.id = "eyedropper-button";
+      eyedropper.className = "devtools-button";
+      /* pointerEvents for eyedropper has to be set auto to display tooltip when
+       * eyedropper is disabled in non-HTML documents.
+       */
+      eyedropper.style.pointerEvents = "auto";
+      container.appendChild(eyedropper);
     }
     widget.inspector = this.inspector;
 
-    let eyedropper = doc.createElementNS(XHTML_NS, "button");
-    eyedropper.id = "eyedropper-button";
-    eyedropper.className = "devtools-button";
-    /* pointerEvents for eyedropper has to be set auto to display tooltip when
-     * eyedropper is disabled in non-HTML documents.
-     */
-    eyedropper.style.pointerEvents = "auto";
-    container.appendChild(eyedropper);
-
     // 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", () => {
       widget.show();
     });
 
     return widget;
   },