Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(906)

Unified Diff: third_party/WebKit/Source/devtools/front_end/ui/CSSShadowEditor.js

Issue 2252913002: DevTools: Box-shadow editor initial implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@shadowIcon
Patch Set: Heavily updated Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
new file mode 100644
index 0000000000000000000000000000000000000000..b7039f889f3f4423585c7b7398ed99d0b3dc9489
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/ui/CSSShadowEditor.js
@@ -0,0 +1,203 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @constructor
+ * @param {!WebInspector.CSSShadowModel} model
+ * @extends {WebInspector.VBox}
+ */
+WebInspector.CSSShadowEditor = function(model)
+{
+ WebInspector.VBox.call(this, true);
+ this.registerRequiredCSS("ui/cssShadowEditor.css");
+ this.contentElement.tabIndex = 0;
+
+ this._model = model;
+
+ this._typeField = this.contentElement.createChild("div", "shadow-editor-field");
+ var label = this._typeField.createChild("label", "shadow-editor-label");
+ label.textContent = WebInspector.UIString("Type");
dgozman 2016/08/24 19:18:30 Inline |label| here.
flandy 2016/08/24 22:08:41 Done.
+ this._outsetButton = this._typeField.createChild("button", "shadow-editor-button left");
dgozman 2016/08/24 19:18:30 "left" is too generic for css class. Let's do shad
flandy 2016/08/24 22:08:41 Done.
+ this._outsetButton.createTextChild(WebInspector.UIString("Outset"));
+ this._outsetButton.addEventListener("click", this._onButtonClick.bind(this), true);
+ this._insetButton = this._typeField.createChild("button", "shadow-editor-button right");
+ this._insetButton.createTextChild(WebInspector.UIString("Inset"));
dgozman 2016/08/24 19:18:30 Just textContent = ... ?
flandy 2016/08/24 22:08:41 Done.
+ this._insetButton.addEventListener("click", this._onButtonClick.bind(this), true);
+
+ var inputs;
+ inputs = this._createSliderField("X offset", true);
dgozman 2016/08/24 19:18:30 Always UIString the literal, do not pass it raw.
flandy 2016/08/24 22:08:41 I called UIString in the function, but I suppose I
+ this._xInput = inputs.textInput;
+ this._xSlider = inputs.rangeInput;
+ inputs = this._createSliderField("Y offset", true);
+ this._yInput = inputs.textInput;
+ this._ySlider = inputs.rangeInput;
+ inputs = this._createSliderField("Blur", false);
+ this._blurInput = inputs.textInput;
+ this._blurSlider = inputs.rangeInput;
+ inputs = this._createSliderField("Spread", false);
+ this._spreadInput = inputs.textInput;
+ this._spreadSlider = inputs.rangeInput;
+ this._spreadField = inputs.field;
+
+ this._updateUI();
+}
+
+/** @enum {symbol} */
+WebInspector.CSSShadowEditor.Events = {
+ ShadowChanged: Symbol("ShadowChanged")
+}
+
+/** @type {number} */
+WebInspector.CSSShadowEditor.maxRange = 40;
+/** @type {string} */
+WebInspector.CSSShadowEditor.defaultUnit = "px";
+
+WebInspector.CSSShadowEditor.prototype = {
+ /**
+ * @param {string} propertyName
+ * @param {boolean} negativeAllowed
+ * @return {{textInput: !Element, rangeInput: !Element, field: !Element}}
+ */
+ _createSliderField: function(propertyName, negativeAllowed)
+ {
+ var field = this.contentElement.createChild("div", "shadow-editor-field");
+ var label = field.createChild("label", "shadow-editor-label");
+ label.textContent = WebInspector.UIString(propertyName);
+ label.htmlFor = propertyName;
dgozman 2016/08/24 19:18:30 Use setAttribute.
flandy 2016/08/24 22:08:41 Done.
+ var textInput = field.createChild("input", "shadow-editor-text-input");
+ textInput.type = "text";
+ textInput.id = propertyName;
+ textInput.addEventListener("input", this._onTextInput.bind(this), true);
dgozman 2016/08/24 19:18:30 Why do we capture all events?
flandy 2016/08/24 22:08:41 We want any valid changes to be reflected immediat
dgozman 2016/08/24 23:26:58 I was talking about last parameter being |true|. S
flandy 2016/08/25 00:17:47 Oh I see, done!
+ textInput.addEventListener("blur", this._onTextBlur.bind(this), true);
+ var halfRange = WebInspector.CSSShadowEditor.maxRange / 2;
+ var slider = negativeAllowed ? createSliderLabel(halfRange * -1, halfRange) : createSliderLabel(0, WebInspector.CSSShadowEditor.maxRange);
dgozman 2016/08/24 19:18:30 -halfRange
flandy 2016/08/24 22:08:41 Done.
+ slider.addEventListener("input", this._onSliderInput.bind(this), true);
+ field.appendChild(slider);
+ return {field: field, textInput: textInput, rangeInput: slider};
+ },
+
+ hideBoxShadowProperties: function()
dgozman 2016/08/24 19:18:30 Isn't this class reused? We should.
flandy 2016/08/24 22:08:41 Is CSSShadowEditor re-used for text-shadows? Yes.
dgozman 2016/08/24 23:26:58 What I meant is that creating an editor every time
flandy 2016/08/25 00:17:47 Thanks for clarifying. Done.
+ {
+ this._typeField.hidden = true;
dgozman 2016/08/24 19:18:30 Figure that out from this._model.
flandy 2016/08/24 22:08:41 Done.
+ this._spreadField.hidden = true;
+ },
+
+ _updateUI: function()
+ {
+ this._updateButtons();
+ this._updateSliders();
+ this._xInput.value = this._model.offsetX().asCSSText();
+ this._yInput.value = this._model.offsetY().asCSSText();
+ this._blurInput.value = this._model.blurRadius().asCSSText();
+ this._spreadInput.value = this._model.spreadRadius().asCSSText();
+ },
+
+ _updateButtons: function()
+ {
+ this._insetButton.classList.toggle("enabled", this._model.inset());
+ this._outsetButton.classList.toggle("enabled", !this._model.inset());
+ },
+
+ _updateSliders: function()
+ {
+ 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;
+ },
+
+ /**
+ * @param {!Event} event
+ */
+ _onButtonClick: function(event)
+ {
+ var insetClicked = (event.currentTarget === this._insetButton);
+ if (insetClicked && this._model.inset() || !insetClicked && !this._model.inset())
+ return;
+ this._model.setInset(insetClicked);
+ this._updateButtons();
+ this.dispatchEventToListeners(WebInspector.CSSShadowEditor.Events.ShadowChanged, this._model);
+ },
+
+ /**
+ * @param {!Event} event
+ */
+ _onTextInput: function(event)
+ {
+ this._changedElement = event.currentTarget;
+ this._changedElement.classList.toggle("invalid", false);
+ var length = WebInspector.CSSLength.parse(event.currentTarget.value);
+ if (!length || event.currentTarget === this._blurInput && length.amount < 0)
+ return;
+ if (event.currentTarget === this._xInput)
+ this._model.setOffset(length, this._model.offsetY());
dgozman 2016/08/24 19:18:30 Why don't we have separate setOffsetX and setOffse
flandy 2016/08/24 22:08:41 Done.
+ else if (event.currentTarget === this._yInput)
+ this._model.setOffset(this._model.offsetX(), length);
+ else if (event.currentTarget === this._blurInput)
+ this._model.setBlurRadius(length);
+ else if (event.currentTarget === this._spreadInput)
+ this._model.setSpreadRadius(length);
+ this._updateSliders();
dgozman 2016/08/24 19:18:30 Let's update them separately as we do for inputs.
flandy 2016/08/24 22:08:41 Done.
+ this.dispatchEventToListeners(WebInspector.CSSShadowEditor.Events.ShadowChanged, this._model);
+ },
+
+ _onTextBlur: function()
+ {
+ if (!this._changedElement)
+ return;
+ var length = this._changedElement.value === "" ? WebInspector.CSSLength.zero() : WebInspector.CSSLength.parse(this._changedElement.value);
dgozman 2016/08/24 19:18:30 x === "" should be !x
flandy 2016/08/24 22:08:41 Done.
+ if (!length)
+ length = WebInspector.CSSLength.parse(this._changedElement.value + WebInspector.CSSShadowEditor.defaultUnit);
+ if (!length) {
+ this._changedElement.classList.add("invalid");
+ this._changedElement = null;
+ return;
+ }
+ if (this._changedElement === this._xInput) {
+ this._model.setOffset(length, this._model.offsetY());
+ this._xInput.value = this._model.offsetX().asCSSText();
+ } else if (this._changedElement === this._yInput) {
+ this._model.setOffset(this._model.offsetX(), length);
+ this._yInput.value = this._model.offsetY().asCSSText();
+ } else if (this._changedElement === this._blurInput) {
+ if (length.amount < 0)
+ length = WebInspector.CSSLength.zero();
+ this._model.setBlurRadius(length);
+ this._blurInput.value = this._model.blurRadius().asCSSText();
+ } else if (this._changedElement === this._spreadInput) {
+ this._model.setSpreadRadius(length);
+ this._spreadInput.value = this._model.spreadRadius().asCSSText();
+ }
+ this._changedElement = null;
+ this._updateSliders();
+ this.dispatchEventToListeners(WebInspector.CSSShadowEditor.Events.ShadowChanged, this._model);
+ },
+
+ /**
+ * @param {!Event} event
+ */
+ _onSliderInput: function(event)
+ {
+ if (event.currentTarget === this._xSlider) {
+ this._model.setOffset(new WebInspector.CSSLength(this._xSlider.value, this._model.offsetX().unit || WebInspector.CSSShadowEditor.defaultUnit), this._model.offsetY());
+ this._xInput.value = this._model.offsetX().asCSSText();
+ this._xInput.classList.toggle("invalid", false);
+ } else if (event.currentTarget === this._ySlider) {
+ this._model.setOffset(this._model.offsetX(), 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) {
+ 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);
+ } else if (event.currentTarget === this._spreadSlider) {
+ this._model.setSpreadRadius(new WebInspector.CSSLength(this._spreadSlider.value, this._model.spreadRadius().unit || WebInspector.CSSShadowEditor.defaultUnit));
+ this._spreadInput.value = this._model.spreadRadius().asCSSText();
+ this._spreadInput.classList.toggle("invalid", false);
+ }
+ this.dispatchEventToListeners(WebInspector.CSSShadowEditor.Events.ShadowChanged, this._model);
+ },
+
+ __proto__: WebInspector.VBox.prototype
+}

Powered by Google App Engine
This is Rietveld 408576698