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

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

Issue 2252913002: DevTools: Box-shadow editor initial implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@shadowIcon
Patch Set: 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/ShadowEditor.js
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/ShadowEditor.js b/third_party/WebKit/Source/devtools/front_end/ui/ShadowEditor.js
index d95a9a8eb007e58cfe40c5f947e94758ef6d3897..8672769c7f998ff7484c8a6cb0dc25a63bab6063 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/ShadowEditor.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/ShadowEditor.js
@@ -4,16 +4,259 @@
/**
* @constructor
+ * @param {!WebInspector.ShadowEditor.Shadow} shadow
+ * @extends {WebInspector.VBox}
*/
-WebInspector.ShadowEditor = function() {}
+WebInspector.ShadowEditor = function(shadow)
+{
+ WebInspector.VBox.call(this, true);
+ this._shadow = shadow;
lushnikov 2016/08/17 17:07:21 this._model = ..
flandy 2016/08/24 18:10:07 Done.
+ this._type = shadow.type();
+ this.registerRequiredCSS("ui/shadowEditor.css");
lushnikov 2016/08/17 17:07:21 this should go as the first line after super-call
flandy 2016/08/24 18:10:07 Done.
+
+ var field, label, slider;
+ if (this._type === "box-shadow") {
+ field = this.contentElement.createChild("div", "shadow-editor-field");
+ label = field.createChild("label");
+ label.textContent = WebInspector.UIString("Type");
+ this._outsetButton = field.createChild("div", "shadow-editor-button left");
+ this._outsetButton.textContent = WebInspector.UIString("Outset");
+ this._outsetButton.addEventListener("click", this._onInsetOutsetClicked.bind(this), true);
+ this._insetButton = field.createChild("div", "shadow-editor-button right");
+ this._insetButton.textContent = WebInspector.UIString("Inset");
+ this._insetButton.addEventListener("click", this._onInsetOutsetClicked.bind(this), true);
+ }
+
+ field = this.contentElement.createChild("div", "shadow-editor-field");
lushnikov 2016/08/17 17:07:21 these look strikingly similar. Maybe it's possible
flandy 2016/08/24 18:10:07 Done.
+ label = field.createChild("label");
+ label.textContent = WebInspector.UIString("X offset");
+ label.for = "shadow-editor-x";
+ this._xInput = field.createChild("input");
+ this._xInput.type = "text";
+ this._xInput.id = "shadow-editor-x";
+ this._xInput.addEventListener("input", this._onTextInput.bind(this), true);
+ slider = field.createChild("div", "shadow-editor-slider");
+ this._xSliderTrack = slider.createChild("div", "shadow-editor-slider-track");
+ this._xSliderThumb = this._xSliderTrack.createChild("div", "shadow-editor-slider-thumb");
+ WebInspector.installDragHandle(slider, this._dragStart.bind(this), this._dragX.bind(this), this._dragX.bind(this), "default");
lushnikov 2016/08/17 17:07:21 can you please attach a screenshot - it's hard to
flandy 2016/08/24 18:10:07 Done.
+
+ field = this.contentElement.createChild("div", "shadow-editor-field");
+ label = field.createChild("label");
+ label.textContent = WebInspector.UIString("Y offset");
+ label.for = "shadow-editor-y";
+ this._yInput = field.createChild("input");
+ this._yInput.type = "text";
+ this._yInput.id = "shadow-editor-y";
+ this._yInput.addEventListener("input", this._onTextInput.bind(this), true);
+ slider = field.createChild("div", "shadow-editor-slider");
+ this._ySliderTrack = slider.createChild("div", "shadow-editor-slider-track");
+ this._ySliderThumb = this._ySliderTrack.createChild("div", "shadow-editor-slider-thumb");
+ WebInspector.installDragHandle(slider, this._dragStart.bind(this), this._dragY.bind(this), this._dragY.bind(this), "default");
lushnikov 2016/08/17 17:07:21 Why not listen to default slider changed events?
flandy 2016/08/24 18:10:07 Done.
+
+ field = this.contentElement.createChild("div", "shadow-editor-field");
+ label = field.createChild("label");
+ label.textContent = WebInspector.UIString("Blur");
+ label.for = "shadow-editor-blur";
+ this._blurInput = field.createChild("input");
+ this._blurInput.type = "text";
+ this._blurInput.id = "shadow-editor-blur";
+ this._blurInput.addEventListener("input", this._onTextInput.bind(this), true);
+ slider = field.createChild("div", "shadow-editor-slider");
+ this._blurSliderTrack = slider.createChild("div", "shadow-editor-slider-track");
+ this._blurSliderThumb = this._blurSliderTrack.createChild("div", "shadow-editor-slider-thumb");
+ WebInspector.installDragHandle(slider, this._dragStart.bind(this), this._dragBlur.bind(this), this._dragBlur.bind(this), "default");
+
+ if (this._type === "box-shadow") {
+ field = this.contentElement.createChild("div", "shadow-editor-field");
+ label = field.createChild("label");
+ label.textContent = WebInspector.UIString("Spread");
+ label.for = "shadow-editor-spread";
+ this._spreadInput = field.createChild("input");
+ this._spreadInput.type = "text";
+ this._spreadInput.id = "shadow-editor-spread";
+ this._spreadInput.addEventListener("input", this._onTextInput.bind(this), true);
+ slider = field.createChild("div", "shadow-editor-slider");
+ this._spreadSliderTrack = slider.createChild("div", "shadow-editor-slider-track");
+ this._spreadSliderThumb = this._spreadSliderTrack.createChild("div", "shadow-editor-slider-thumb");
+ WebInspector.installDragHandle(slider, this._dragStart.bind(this), this._dragSpread.bind(this), this._dragSpread.bind(this), "default");
+ }
+}
+
+WebInspector.ShadowEditor.Events = {
+ ShadowChanged: "ShadowChanged"
+}
+
+/** @type {number} */
+WebInspector.ShadowEditor.maxSliderValue = 25;
+
+WebInspector.ShadowEditor.prototype = {
+ /**
+ * @override
+ */
+ wasShown: function()
+ {
+ this._sliderTrackWidth = this._blurSliderTrack.offsetWidth;
dgozman 2016/08/17 17:42:09 Should we use measureElement instead?
flandy 2016/08/24 18:10:06 Removed.
+ this._halfSliderThumbWidth = this._blurSliderThumb.offsetWidth / 2;
+ this._updateUI();
+ },
+
+ _updateUI: function()
+ {
+ this._updateTextInputs();
+ this._updateSliders();
+ if (this._type === "box-shadow") {
+ this._insetButton.classList.toggle("enabled", this._shadow.inset());
+ this._outsetButton.classList.toggle("enabled", !this._shadow.inset());
+ }
+ },
+
+ _updateTextInputs: function()
+ {
+ this._xInput.value = this._shadow.xOffset().toString();
+ this._yInput.value = this._shadow.yOffset().toString();
+ this._blurInput.value = this._shadow.blur().toString();
+ if (this._type === "box-shadow")
dgozman 2016/08/17 17:42:09 We should either make "box-shadow" a named constan
flandy 2016/08/24 18:10:07 Let's hide fields that are not needed.
+ this._spreadInput.value = this._shadow.spread().toString();
+ },
+
+ _updateSliders: function()
+ {
+ updateSlider.call(this, this._xSliderThumb, this._shadow.xOffset().amount, true);
+ updateSlider.call(this, this._ySliderThumb, this._shadow.yOffset().amount, true);
+ updateSlider.call(this, this._blurSliderThumb, this._shadow.blur().amount, false);
+ if (this._type === "box-shadow")
+ updateSlider.call(this, this._spreadSliderThumb, this._shadow.spread().amount, false);
+
+ /**
+ * @param {!Element} thumb
+ * @param {number} amount
+ * @param {boolean} negativeAllowed
+ * @this {WebInspector.ShadowEditor}
+ */
+ function updateSlider(thumb, amount, negativeAllowed)
+ {
+ amount = Number.constrain(amount, WebInspector.ShadowEditor.maxSliderValue * -1, WebInspector.ShadowEditor.maxSliderValue);
+ var percent = amount / WebInspector.ShadowEditor.maxSliderValue;
+ if (negativeAllowed) {
+ if (amount < 0)
+ percent = (amount + WebInspector.ShadowEditor.maxSliderValue) / WebInspector.ShadowEditor.maxSliderValue / 2;
+ else
+ percent = amount / WebInspector.ShadowEditor.maxSliderValue / 2 + 0.5;
+ }
+ thumb.style.left = (Number.constrain(percent, 0, 1) * this._sliderTrackWidth - this._halfSliderThumbWidth) + "px";
+ }
+ },
+
+ /**
+ * @param {!MouseEvent} event
+ * @return {boolean}
+ */
+ _dragStart: function(event)
+ {
+ this._sliderTrackLeft = this._blurSliderTrack.totalOffsetLeft();
+ return true;
+ },
+
+ /**
+ * @param {!MouseEvent} event
+ */
+ _dragX: function(event)
+ {
+ this._shadow.setXAmount(this._amountFromSlider(event, true));
+ this._onSliderChange();
+ },
+
+ /**
+ * @param {!MouseEvent} event
+ */
+ _dragY: function(event)
+ {
+ this._shadow.setYAmount(this._amountFromSlider(event, true));
+ this._onSliderChange();
+ },
+
+ /**
+ * @param {!MouseEvent} event
+ */
+ _dragBlur: function(event)
+ {
+ this._shadow.setBlurAmount(this._amountFromSlider(event, false));
+ this._onSliderChange();
+ },
+
+ /**
+ * @param {!MouseEvent} event
+ */
+ _dragSpread: function(event)
dgozman 2016/08/17 17:42:09 I'm curious why default slider handling doesn't wo
flandy 2016/08/24 18:10:07 Changed to use a default range input with custom s
+ {
+ this._shadow.setSpreadAmount(this._amountFromSlider(event, false));
+ this._onSliderChange();
+ },
+
+ /**
+ * @param {!MouseEvent} event
+ * @param {boolean} negativeAllowed
+ * @return {number}
+ */
+ _amountFromSlider: function(event, negativeAllowed)
+ {
+ var offsetX = event.x - this._sliderTrackLeft;
+ var percent = Number.constrain(offsetX / this._sliderTrackWidth, 0, 1);
+ if (!negativeAllowed)
+ return Math.round(percent * WebInspector.ShadowEditor.maxSliderValue);
+
+ var amount;
+ if (percent < 0.5) {
+ percent = percent * 2;
+ amount = percent * WebInspector.ShadowEditor.maxSliderValue - WebInspector.ShadowEditor.maxSliderValue;
+ } else {
+ percent = (percent - 0.5) * 2;
+ amount = percent * WebInspector.ShadowEditor.maxSliderValue
+ }
+ return Math.round(amount);
+ },
+
+ _onSliderChange: function()
+ {
+ this._updateSliders();
+ this._updateTextInputs();
+ this.dispatchEventToListeners(WebInspector.ShadowEditor.Events.ShadowChanged, this._shadow);
+ },
+
+ _onInsetOutsetClicked: function()
+ {
+ this._insetButton.classList.toggle("enabled");
+ this._outsetButton.classList.toggle("enabled");
+ this._shadow.setInset(this._insetButton.classList.contains("enabled"));
+ this.dispatchEventToListeners(WebInspector.ShadowEditor.Events.ShadowChanged, this._shadow);
+ },
+
+ /**
+ * @param {!Event} event
+ */
+ _onTextInput: function(event)
+ {
+ if (WebInspector.ShadowEditor.Length.parse(event.currentTarget.value)) {
+ this._shadow.setXOffset(this._xInput.value);
+ this._shadow.setYOffset(this._yInput.value);
+ this._shadow.setBlur(this._blurInput.value);
+ if (this._type === "box-shadow")
+ this._shadow.setSpread(this._spreadInput.value);
+ this._updateSliders();
+ this.dispatchEventToListeners(WebInspector.ShadowEditor.Events.ShadowChanged, this._shadow);
+ }
+ },
+
+ __proto__: WebInspector.VBox.prototype
+}
/**
* @constructor
*/
WebInspector.ShadowEditor.Shadow = function(type)
{
- this.type = type;
- this.order = [];
+ this._type = type;
+ this._order = [];
}
/**
@@ -28,7 +271,7 @@ WebInspector.ShadowEditor.Shadow.Parts = {
/**
* @param {string} text
* @param {string} type
- * @return {?Array<!WebInspector.ShadowEditor.Shadow>}
+ * @return {!Array<!WebInspector.ShadowEditor.Shadow>}
*/
WebInspector.ShadowEditor.Shadow.parse = function(text, type)
{
@@ -48,24 +291,43 @@ WebInspector.ShadowEditor.Shadow.parse = function(text, type)
var shadows = [];
for (var i = 0; i < shadowTexts.length; i++) {
var shadow = new WebInspector.ShadowEditor.Shadow(type);
+ var order = [];
var regexes = [/inset/g, WebInspector.Color.Regex, WebInspector.ShadowEditor.Length.Regex];
var results = WebInspector.TextUtils.splitStringByRegexes(shadowTexts[i], regexes);
+ var numLengths = 0;
for (var j = 0; j < results.length; j++) {
var result = results[j];
if (result.regexIndex === 0) {
- shadow.setInset(result.value);
+ shadow.setInset(true);
+ order.push(WebInspector.ShadowEditor.Shadow.Parts.Inset);
} else if (result.regexIndex === 1) {
- var color = WebInspector.Color.parse(result.value);
- if (!color)
- return null;
- shadow.setColor(color);
+ shadow.setColor(result.value)
+ order.push(WebInspector.ShadowEditor.Shadow.Parts.Color);
} else if (result.regexIndex === 2) {
- var length = WebInspector.ShadowEditor.Length.parse(result.value);
- if (!length)
- return null;
- shadow.addLength(length);
+ switch (numLengths) {
+ case 0:
+ shadow.setXOffset(result.value);
+ order.push(WebInspector.ShadowEditor.Shadow.Parts.Length);
+ break;
+ case 1:
+ shadow.setYOffset(result.value);
+ break;
+ case 2:
+ shadow.setBlur(result.value);
+ break;
+ case 3:
+ shadow.setSpread(result.value);
+ }
+ numLengths++;
}
}
+ // If inset is not specified, set inset to appear first in the css text by default.
+ if (!order.find(part => part === WebInspector.ShadowEditor.Shadow.Parts.Inset))
+ order.unshift(WebInspector.ShadowEditor.Shadow.Parts.Inset);
+ // If color is not specified, set color to appear last in the css text by default.
+ if (!order.find(part => part === WebInspector.ShadowEditor.Shadow.Parts.Color))
+ order.push(WebInspector.ShadowEditor.Shadow.Parts.Color);
+ shadow.setOrder(order);
shadows.push(shadow);
}
return shadows;
@@ -73,56 +335,183 @@ WebInspector.ShadowEditor.Shadow.parse = function(text, type)
WebInspector.ShadowEditor.Shadow.prototype = {
/**
- * @param {string} inset
+ * @param {!Array<string>} order
+ */
+ setOrder: function(order)
+ {
+ this._order = order;
+ },
+
+ /**
+ * @param {boolean} inset
*/
setInset: function(inset)
{
- if (!this.inset)
- this.order.push(WebInspector.ShadowEditor.Shadow.Parts.Inset);
- this.inset = inset;
+ this._inset = inset;
+ },
+
+ /**
+ * @param {string} text
+ */
+ setColor: function(text)
+ {
+ var color = WebInspector.Color.parse(text);
+ if (color)
+ this._color = color;
+ },
+
+ /**
+ * @param {string} text
+ */
+ setXOffset: function(text)
+ {
+ var length = WebInspector.ShadowEditor.Length.parse(text);
+ if (length)
+ this._xOffset = length;
+ },
+
+ /**
+ * @param {string} text
+ */
+ setYOffset: function(text)
+ {
+ var length = WebInspector.ShadowEditor.Length.parse(text);
+ if (length)
+ this._yOffset = length;
},
/**
- * @param {!WebInspector.Color} color
+ * @param {string} text
*/
- setColor: function(color)
+ setBlur: function(text)
{
- if (!this.color)
- this.order.push(WebInspector.ShadowEditor.Shadow.Parts.Color);
- this.color = color;
+ var length = WebInspector.ShadowEditor.Length.parse(text);
+ if (length)
+ this._blur = length;
},
/**
- * @param {!WebInspector.ShadowEditor.Length} length
+ * @param {string} text
*/
- addLength: function(length)
+ setSpread: function(text)
{
- if (!this.xOffset) {
- this.order.push(WebInspector.ShadowEditor.Shadow.Parts.Length);
- this.xOffset = length;
- } else if (!this.yOffset) {
- this.yOffset = length;
- } else if (!this.blur) {
- this.blur = length;
- } else if (!this.spread) {
- this.spread = length;
+ var length = WebInspector.ShadowEditor.Length.parse(text);
+ if (length) {
+ if (!this._blur)
+ this._blur = new WebInspector.ShadowEditor.Length(0, "");
+ this._spread = length;
}
},
/**
+ * @param {number} amount
+ */
+ setXAmount: function(amount)
+ {
+ if (this._xOffset && this._xOffset.unit)
+ this._xOffset.amount = amount;
+ else
+ this._xOffset = new WebInspector.ShadowEditor.Length(amount, "px");
+ },
+
+ /**
+ * @param {number} amount
+ */
+ setYAmount: function(amount)
+ {
+ if (this._yOffset && this._yOffset.unit)
+ this._yOffset.amount = amount;
+ else
+ this._yOffset = new WebInspector.ShadowEditor.Length(amount, "px");
+ },
+
+
+ /**
+ * @param {number} amount
+ */
+ setBlurAmount: function(amount)
+ {
+ if (this._blur && this._blur.unit)
+ this._blur.amount = amount;
+ else
+ this._blur = new WebInspector.ShadowEditor.Length(amount, "px");
+ },
+
+ /**
+ * @param {number} amount
+ */
+ setSpreadAmount: function(amount)
+ {
+ if (!this._blur)
+ this._blur = new WebInspector.ShadowEditor.Length(0, "");
+ if (this._spread && this._spread.unit)
+ this._spread.amount = amount;
+ else
+ this._spread = new WebInspector.ShadowEditor.Length(amount, "px");
+ },
+
+ /**
+ * @return {string}
+ */
+ type: function()
+ {
+ return this._type;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ inset: function()
+ {
+ return !!this._inset;
+ },
+
+ /**
+ * @return {!WebInspector.ShadowEditor.Length}
+ */
+ xOffset: function()
+ {
+ return this._xOffset ? this._xOffset : new WebInspector.ShadowEditor.Length(0, "");
+ },
+
+ /**
+ * @return {!WebInspector.ShadowEditor.Length}
+ */
+ yOffset: function()
+ {
+ return this._yOffset ? this._yOffset : new WebInspector.ShadowEditor.Length(0, "");
+ },
+
+ /**
+ * @return {!WebInspector.ShadowEditor.Length}
+ */
+ blur: function()
+ {
+ return this._blur ? this._blur : new WebInspector.ShadowEditor.Length(0, "");
+ },
+
+ /**
+ * @return {!WebInspector.ShadowEditor.Length}
+ */
+ spread: function()
+ {
+ return this._spread ? this._spread : new WebInspector.ShadowEditor.Length(0, "");
+ },
+
+ /**
* @return {!Array<!WebInspector.ShadowEditor.Length>}
*/
- lengths: function()
+ _lengths: function()
{
var lengthValues = [];
- if (this.xOffset)
- lengthValues.push(this.xOffset);
- if (this.yOffset)
- lengthValues.push(this.yOffset);
- if (this.blur)
- lengthValues.push(this.blur);
- if (this.spread)
- lengthValues.push(this.spread);
+ if (this._xOffset)
+ lengthValues.push(this._xOffset);
+ if (this._yOffset)
+ lengthValues.push(this._yOffset);
+ if (this._blur)
+ lengthValues.push(this._blur);
+ if (this._spread)
+ lengthValues.push(this._spread);
return lengthValues;
},
@@ -132,19 +521,21 @@ WebInspector.ShadowEditor.Shadow.prototype = {
textParts: function()
{
var parts = [];
- for (var i = 0; i < this.order.length; i++) {
- var currentPart = this.order[i];
- var textValue;
- if (currentPart === WebInspector.ShadowEditor.Shadow.Parts.Inset)
- textValue = this.inset;
+ for (var i = 0; i < this._order.length; i++) {
+ var currentPart = this._order[i];
+ var textValue = null;
+ if (currentPart === WebInspector.ShadowEditor.Shadow.Parts.Inset && this._inset)
+ textValue = "inset";
else if (currentPart === WebInspector.ShadowEditor.Shadow.Parts.Length)
- textValue = this.lengths().join(" ");
- else if (currentPart === WebInspector.ShadowEditor.Shadow.Parts.Color)
- textValue = this.color.asString(this.color.format());
- parts.push({
- type: currentPart,
- text: textValue
- });
+ textValue = this._lengths().join(" ");
+ else if (currentPart === WebInspector.ShadowEditor.Shadow.Parts.Color && this._color)
+ textValue = this._color.asString(this._color.format());
+ if (textValue !== null) {
+ parts.push({
+ type: currentPart,
+ text: textValue
+ });
+ }
}
return parts;
}

Powered by Google App Engine
This is Rietveld 408576698