Chromium Code Reviews| Index: third_party/WebKit/Source/devtools/front_end/ui/CSSShadowEditor.js |
| diff --git a/third_party/WebKit/Source/devtools/front_end/ui/CSSShadowEditor.js b/third_party/WebKit/Source/devtools/front_end/ui/CSSShadowEditor.js |
| index 74a23375f05e4e34776ea655363b76441b91a928..d40d339f714b88d262cf12141bc3d0528336d64c 100644 |
| --- a/third_party/WebKit/Source/devtools/front_end/ui/CSSShadowEditor.js |
| +++ b/third_party/WebKit/Source/devtools/front_end/ui/CSSShadowEditor.js |
| @@ -21,20 +21,27 @@ WebInspector.CSSShadowEditor = function() |
| this._insetButton.textContent = WebInspector.UIString("Inset"); |
| this._insetButton.addEventListener("click", this._onButtonClick.bind(this), false); |
| - var inputs; |
| - inputs = this._createSliderField(WebInspector.UIString("X offset"), true); |
| - this._xInput = inputs.textInput; |
| - this._xSlider = inputs.rangeInput; |
| - inputs = this._createSliderField(WebInspector.UIString("Y offset"), true); |
| - this._yInput = inputs.textInput; |
| - this._ySlider = inputs.rangeInput; |
| - inputs = this._createSliderField(WebInspector.UIString("Blur"), false); |
| - this._blurInput = inputs.textInput; |
| - this._blurSlider = inputs.rangeInput; |
| - inputs = this._createSliderField(WebInspector.UIString("Spread"), false); |
| - this._spreadInput = inputs.textInput; |
| - this._spreadSlider = inputs.rangeInput; |
| - this._spreadField = inputs.field; |
| + var xField = this.contentElement.createChild("div", "shadow-editor-field"); |
| + this._xInput = this._createTextInput(xField, WebInspector.UIString("X offset")); |
| + var yField = this.contentElement.createChild("div", "shadow-editor-field"); |
| + this._yInput = this._createTextInput(yField, WebInspector.UIString("Y offset")); |
| + this._xySlider = xField.createChild("canvas", "shadow-editor-2D-slider"); |
| + this._xySlider.width = WebInspector.CSSShadowEditor.canvasSize; |
| + this._xySlider.height = WebInspector.CSSShadowEditor.canvasSize; |
| + this._xySlider.tabIndex = -1; |
| + this._halfCanvasSize = WebInspector.CSSShadowEditor.canvasSize / 2; |
| + this._innerCanvasSize = this._halfCanvasSize - WebInspector.CSSShadowEditor.sliderThumbRadius; |
| + WebInspector.installDragHandle(this._xySlider, this._dragStart.bind(this), this._dragMove.bind(this), null, "default"); |
| + this._xySlider.addEventListener("keydown", this._onCanvasUpDown.bind(this), false); |
| + this._xySlider.addEventListener("blur", this._onCanvasBlur.bind(this), false); |
| + |
| + var blurField = this.contentElement.createChild("div", "shadow-editor-blur-field"); |
| + this._blurInput = this._createTextInput(blurField, WebInspector.UIString("Blur")); |
| + this._blurSlider = this._createSlider(blurField); |
| + |
| + this._spreadField = this.contentElement.createChild("div", "shadow-editor-field"); |
| + this._spreadInput = this._createTextInput(this._spreadField, WebInspector.UIString("Spread")); |
| + this._spreadSlider = this._createSlider(this._spreadField); |
| } |
| /** @enum {symbol} */ |
| @@ -43,19 +50,22 @@ WebInspector.CSSShadowEditor.Events = { |
| } |
| /** @type {number} */ |
| -WebInspector.CSSShadowEditor.maxRange = 40; |
| +WebInspector.CSSShadowEditor.maxRange = 20; |
| /** @type {string} */ |
| WebInspector.CSSShadowEditor.defaultUnit = "px"; |
| +/** @type {number} */ |
| +WebInspector.CSSShadowEditor.sliderThumbRadius = 6; |
| +/** @type {number} */ |
| +WebInspector.CSSShadowEditor.canvasSize = 88; |
| WebInspector.CSSShadowEditor.prototype = { |
| /** |
| + * @param {!Element} field |
| * @param {string} propertyName |
| - * @param {boolean} negativeAllowed |
| - * @return {{textInput: !Element, rangeInput: !Element, field: !Element}} |
| + * @return {!Element} |
| */ |
| - _createSliderField: function(propertyName, negativeAllowed) |
| + _createTextInput: function(field, propertyName) |
| { |
| - var field = this.contentElement.createChild("div", "shadow-editor-field"); |
| var label = field.createChild("label", "shadow-editor-label"); |
| label.textContent = propertyName; |
| label.setAttribute("for", propertyName); |
| @@ -66,11 +76,19 @@ WebInspector.CSSShadowEditor.prototype = { |
| textInput.addEventListener("mousewheel", this._handleValueModification.bind(this), false); |
| textInput.addEventListener("input", this._onTextInput.bind(this), false); |
| textInput.addEventListener("blur", this._onTextBlur.bind(this), false); |
| - var halfRange = WebInspector.CSSShadowEditor.maxRange / 2; |
| - var slider = negativeAllowed ? createSliderLabel(-halfRange, halfRange) : createSliderLabel(0, WebInspector.CSSShadowEditor.maxRange); |
| + return textInput; |
| + }, |
| + |
| + /** |
| + * @param {!Element} field |
| + * @return {!Element} |
| + */ |
| + _createSlider: function(field) |
| + { |
| + var slider = createSliderLabel(0, WebInspector.CSSShadowEditor.maxRange, -1); |
| slider.addEventListener("input", this._onSliderInput.bind(this), false); |
| field.appendChild(slider); |
| - return {field: field, textInput: textInput, rangeInput: slider}; |
| + return slider; |
| }, |
| /** |
| @@ -99,10 +117,9 @@ WebInspector.CSSShadowEditor.prototype = { |
| this._yInput.value = this._model.offsetY().asCSSText(); |
| this._blurInput.value = this._model.blurRadius().asCSSText(); |
| this._spreadInput.value = this._model.spreadRadius().asCSSText(); |
| - this._xSlider.value = this._model.offsetX().amount; |
| - this._ySlider.value = this._model.offsetY().amount; |
| this._blurSlider.value = this._model.blurRadius().amount; |
| this._spreadSlider.value = this._model.spreadRadius().amount; |
| + this._updateCanvas(); |
| }, |
| _updateButtons: function() |
| @@ -111,6 +128,47 @@ WebInspector.CSSShadowEditor.prototype = { |
| this._outsetButton.classList.toggle("enabled", !this._model.inset()); |
| }, |
| + _updateCanvas: function() |
| + { |
| + var context = this._xySlider.getContext("2d"); |
| + context.clearRect(0, 0, this._xySlider.width, this._xySlider.height); |
| + |
| + // Draw dashed axes. |
| + context.save(); |
| + context.setLineDash([1, 1]); |
| + context.strokeStyle = "rgba(0, 0, 0, 0.2)"; |
| + context.beginPath(); |
| + context.moveTo(this._halfCanvasSize, 0); |
| + context.lineTo(this._halfCanvasSize, WebInspector.CSSShadowEditor.canvasSize); |
| + context.moveTo(0, this._halfCanvasSize); |
| + context.lineTo(WebInspector.CSSShadowEditor.canvasSize, this._halfCanvasSize); |
| + context.stroke(); |
| + context.restore(); |
| + |
| + var thumbPoint = this._sliderThumbPosition(); |
| + // Draw 2D slider line. |
| + context.save(); |
| + context.translate(this._halfCanvasSize, this._halfCanvasSize); |
| + context.lineWidth = 2; |
| + context.strokeStyle = "rgba(0, 0, 0, 0.3)"; |
| + context.beginPath(); |
| + context.moveTo(0, 0); |
| + context.lineTo(thumbPoint.x, thumbPoint.y); |
| + context.stroke(); |
| + // Draw 2D slider thumb. |
| + context.beginPath(); |
| + if (this._xySlider.hasFocus) { |
| + context.fillStyle = "rgba(66, 133, 244, 0.4)"; |
| + context.arc(thumbPoint.x, thumbPoint.y, WebInspector.CSSShadowEditor.sliderThumbRadius + 2, 0, 2 * Math.PI); |
| + context.fill(); |
| + } |
| + context.beginPath() |
| + context.fillStyle = "#4285F4"; |
| + context.arc(thumbPoint.x, thumbPoint.y, WebInspector.CSSShadowEditor.sliderThumbRadius, 0, 2 * Math.PI); |
| + context.fill(); |
| + context.restore(); |
| + }, |
| + |
| /** |
| * @param {!Event} event |
| */ |
| @@ -169,10 +227,10 @@ WebInspector.CSSShadowEditor.prototype = { |
| return; |
| if (event.currentTarget === this._xInput) { |
| this._model.setOffsetX(length); |
| - this._xSlider.value = length.amount; |
| + this._updateCanvas(); |
| } else if (event.currentTarget === this._yInput) { |
| this._model.setOffsetY(length); |
| - this._ySlider.value = length.amount; |
| + this._updateCanvas(); |
| } else if (event.currentTarget === this._blurInput) { |
| this._model.setBlurRadius(length); |
| this._blurSlider.value = length.amount; |
| @@ -187,7 +245,7 @@ WebInspector.CSSShadowEditor.prototype = { |
| { |
| if (!this._changedElement) |
| return; |
| - var length = !this._changedElement.value ? WebInspector.CSSLength.zero() : WebInspector.CSSLength.parse(this._changedElement.value); |
| + var length = !this._changedElement.value.trim() ? WebInspector.CSSLength.zero() : WebInspector.CSSLength.parse(this._changedElement.value); |
| if (!length) |
| length = WebInspector.CSSLength.parse(this._changedElement.value + WebInspector.CSSShadowEditor.defaultUnit); |
| if (!length) { |
| @@ -198,11 +256,11 @@ WebInspector.CSSShadowEditor.prototype = { |
| if (this._changedElement === this._xInput) { |
| this._model.setOffsetX(length); |
| this._xInput.value = length.asCSSText(); |
| - this._xSlider.value = length.amount; |
| + this._updateCanvas(); |
| } else if (this._changedElement === this._yInput) { |
| this._model.setOffsetY(length); |
| this._yInput.value = length.asCSSText(); |
| - this._ySlider.value = length.amount; |
| + this._updateCanvas(); |
| } else if (this._changedElement === this._blurInput) { |
| if (length.amount < 0) |
| length = WebInspector.CSSLength.zero(); |
| @@ -223,15 +281,7 @@ WebInspector.CSSShadowEditor.prototype = { |
| */ |
| _onSliderInput: function(event) |
| { |
| - if (event.currentTarget === this._xSlider) { |
| - this._model.setOffsetX(new WebInspector.CSSLength(this._xSlider.value, this._model.offsetX().unit || WebInspector.CSSShadowEditor.defaultUnit)); |
| - this._xInput.value = this._model.offsetX().asCSSText(); |
| - this._xInput.classList.toggle("invalid", false); |
| - } else if (event.currentTarget === this._ySlider) { |
| - this._model.setOffsetY(new WebInspector.CSSLength(this._ySlider.value, this._model.offsetY().unit || WebInspector.CSSShadowEditor.defaultUnit)); |
| - this._yInput.value = this._model.offsetY().asCSSText(); |
| - this._yInput.classList.toggle("invalid", false); |
| - } else if (event.currentTarget === this._blurSlider) { |
| + if (event.currentTarget === this._blurSlider) { |
| this._model.setBlurRadius(new WebInspector.CSSLength(this._blurSlider.value, this._model.blurRadius().unit || WebInspector.CSSShadowEditor.defaultUnit)); |
| this._blurInput.value = this._model.blurRadius().asCSSText(); |
| this._blurInput.classList.toggle("invalid", false); |
| @@ -243,5 +293,109 @@ WebInspector.CSSShadowEditor.prototype = { |
| this.dispatchEventToListeners(WebInspector.CSSShadowEditor.Events.ShadowChanged, this._model); |
| }, |
| + /** |
| + * @param {!Event} event |
| + * @return {boolean} |
| + */ |
| + _dragStart: function(event) |
| + { |
| + if (event.currentTarget === this._xySlider) { |
| + this._xySlider.focus(); |
| + this._xySlider.hasFocus = true; |
|
lushnikov
2016/08/30 19:22:19
let's not add fields to the DOM wrappers - i think
flandy
2016/08/30 22:50:42
Done. I've added Document.prototype.deepActiveElem
|
| + } |
| + this._canvasOrigin = new WebInspector.Geometry.Point(this._xySlider.totalOffsetLeft() + this._halfCanvasSize, this._xySlider.totalOffsetTop() + this._halfCanvasSize); |
| + var clickedPoint = new WebInspector.Geometry.Point(event.x - this._canvasOrigin.x, event.y - this._canvasOrigin.y); |
| + var thumbPoint = this._sliderThumbPosition(); |
| + if (clickedPoint.distanceTo(thumbPoint) >= WebInspector.CSSShadowEditor.sliderThumbRadius) |
| + this._dragMove(event); |
| + return true; |
| + }, |
| + |
| + /** |
| + * @param {!Event} event |
| + */ |
| + _dragMove: function(event) |
| + { |
| + var point = new WebInspector.Geometry.Point(event.x - this._canvasOrigin.x, event.y - this._canvasOrigin.y); |
|
lushnikov
2016/08/30 19:22:19
nit: excessive spaces
flandy
2016/08/30 22:50:42
Done.
|
| + var constrainedPoint = this._constrainPoint(point, this._innerCanvasSize); |
| + var newX = Math.round((constrainedPoint.x / this._innerCanvasSize) * WebInspector.CSSShadowEditor.maxRange); |
| + var newY = Math.round((constrainedPoint.y / this._innerCanvasSize) * WebInspector.CSSShadowEditor.maxRange); |
| + this._model.setOffsetX(new WebInspector.CSSLength(newX, this._model.offsetX().unit || WebInspector.CSSShadowEditor.defaultUnit)); |
| + this._model.setOffsetY(new WebInspector.CSSLength(newY, this._model.offsetY().unit || WebInspector.CSSShadowEditor.defaultUnit)); |
| + this._xInput.value = this._model.offsetX().asCSSText(); |
| + this._yInput.value = this._model.offsetY().asCSSText(); |
| + this._xInput.classList.toggle("invalid", false); |
|
lushnikov
2016/08/30 19:22:19
nit: this._xInput.classList.remove("invalid")
flandy
2016/08/30 22:50:42
Done.
|
| + this._yInput.classList.toggle("invalid", false); |
| + this._updateCanvas(); |
| + this.dispatchEventToListeners(WebInspector.CSSShadowEditor.Events.ShadowChanged, this._model); |
| + }, |
| + |
| + _onCanvasBlur: function() |
| + { |
| + this._xySlider.hasFocus = false; |
| + this._updateCanvas(); |
| + }, |
| + |
| + /** |
| + * @param {!Event} event |
| + */ |
| + _onCanvasUpDown: function(event) |
| + { |
| + var upDown = (event.key === "ArrowUp" || event.key === "ArrowDown"); |
|
lushnikov
2016/08/30 19:22:19
can we use WI.KeyboardShortcuts for key detection?
flandy
2016/08/30 22:50:41
This seems unnecessary here. Also, keyCode is depr
|
| + var leftRight = (event.key === "ArrowRight" || event.key === "ArrowLeft") |
| + if (!upDown && !leftRight || !this._xySlider.hasFocus) |
|
lushnikov
2016/08/30 19:22:19
how could it be non-focused? doesn't even triggeri
flandy
2016/08/30 22:50:41
Yes good point. Removed.
|
| + return |
|
lushnikov
2016/08/30 19:22:19
; missing
flandy
2016/08/30 22:50:41
Done.
|
| + event.consume(true); |
| + |
| + var newAmount; |
| + if (upDown) { |
| + var offsetY = this._model.offsetY(); |
| + newAmount = event.key === "ArrowUp" ? offsetY.amount - 1 : offsetY.amount + 1; |
|
lushnikov
2016/08/30 19:22:19
Let's compare for event.key only only once, in the
flandy
2016/08/30 22:50:41
Done.
|
| + newAmount = Number.constrain(newAmount, -WebInspector.CSSShadowEditor.maxRange, WebInspector.CSSShadowEditor.maxRange); |
| + this._model.setOffsetY(new WebInspector.CSSLength(newAmount, offsetY.unit || WebInspector.CSSShadowEditor.defaultUnit)); |
| + this._yInput.value = this._model.offsetY().asCSSText(); |
| + this._yInput.classList.toggle("invalid", false); |
| + } else if (leftRight) { |
| + var offsetX = this._model.offsetX() |
| + newAmount = event.key === "ArrowRight" ? offsetX.amount + 1 : offsetX.amount - 1; |
| + newAmount = Number.constrain(newAmount, -WebInspector.CSSShadowEditor.maxRange, WebInspector.CSSShadowEditor.maxRange); |
| + this._model.setOffsetX(new WebInspector.CSSLength(newAmount, offsetX.unit || WebInspector.CSSShadowEditor.defaultUnit)); |
| + this._xInput.value = this._model.offsetX().asCSSText(); |
| + this._xInput.classList.toggle("invalid", false); |
| + } |
| + this._updateCanvas(); |
| + this.dispatchEventToListeners(WebInspector.CSSShadowEditor.Events.ShadowChanged, this._model); |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.Geometry.Point} point |
| + * @param {number} max |
| + * @return {!WebInspector.Geometry.Point} |
| + */ |
| + _constrainPoint: function(point, max) |
| + { |
| + var newPoint = new WebInspector.Geometry.Point(point.x, point.y); |
| + if ((Math.abs(point.x) <= max && Math.abs(point.y) <= max) || (point.x === 0 && point.y === 0)) |
|
lushnikov
2016/08/30 19:22:19
why special case for zeroes?
flandy
2016/08/30 22:50:42
To avoid divide by zero if max < 0. I never use ma
|
| + return newPoint; |
| + if (Math.abs(point.x) > Math.abs(point.y)) { |
|
lushnikov
2016/08/30 19:22:19
the function could be written simpler:
if (Mat
flandy
2016/08/30 22:50:41
Thanks! Done.
|
| + newPoint.x = point.x < 0 ? -max : max; |
| + newPoint.y = newPoint.x * point.y / point.x; |
| + } else { |
| + newPoint.y = point.y < 0 ? -max : max; |
| + newPoint.x = newPoint.y * point.x / point.y; |
| + } |
| + return newPoint; |
| + }, |
| + |
| + /** |
| + * @return {!WebInspector.Geometry.Point} |
| + */ |
| + _sliderThumbPosition: function() |
| + { |
| + var x = (this._model.offsetX().amount / WebInspector.CSSShadowEditor.maxRange) * this._innerCanvasSize; |
| + var y = (this._model.offsetY().amount / WebInspector.CSSShadowEditor.maxRange) * this._innerCanvasSize; |
| + return this._constrainPoint(new WebInspector.Geometry.Point(x, y), this._innerCanvasSize); |
| + }, |
| + |
| __proto__: WebInspector.VBox.prototype |
| -} |
| +} |