Skip to content

Commit 127fc17

Browse files
feihaozi77gideonthomas
authored andcommitted
Add Border Radius Inline editor (#890)
Fix mozilla/thimble.mozilla.org#2506 * Added all components for Border Radius Inline editor * remove text selection after closing inline border radius editor * made allCornerSlider and individual slider work seperately without effecting each other * added the slider value indicator * modified BorderRadiusEditor to allow keeping all units(%,em,px) * modified BorderRadiusEditor to allow keeping all units(%,em,px)--#2 * added radio buttons to toggle slider unit * making individual corner values sync with allcorner mode value * Border UI updates * fixed when close inlineEditor the cursor do not go to top * Light theme + CSS cleanup * code cleaned up * fixed indentation and replaceAll() local function * fixed some indentations * removed _values local property from borderRadiusEditor.js * Fixed few indentations and comments * added comment for borderRadiusUtil * added more comments in borderRadiusUtils.js * Fixed few comments * Review fixes * Fixed some codes according to comments from gide * fixed indentation * fixed indentation 2x
1 parent ef1aa27 commit 127fc17

File tree

8 files changed

+1236
-0
lines changed

8 files changed

+1236
-0
lines changed

src/extensions/bramble-extensions.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,18 @@
5757
"extensions/default/InlineColorEditor/img/*.png"
5858
]
5959
},
60+
{
61+
"path": "extensions/default/InlineBorderRadiusEditor",
62+
"less": {
63+
"dist/extensions/default/InlineBorderRadiusEditor/css/main.css": [
64+
"src/extensions/default/InlineBorderRadiusEditor/css/main.less"
65+
]
66+
},
67+
"copy": [
68+
"extensions/default/InlineBorderRadiusEditor/img/*.png",
69+
"extensions/default/InlineBorderRadiusEditor/BorderRadiusEditorTemplate.html"
70+
]
71+
},
6072
{
6173
"path": "extensions/default/Inline3DParametersEditor",
6274
"less": {
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
define(function(require, exports, module) {
2+
"use strict";
3+
4+
var Strings = brackets.getModule("strings");
5+
var Mustache = brackets.getModule("thirdparty/mustache/mustache");
6+
var BorderRadiusUtils = require("BorderRadiusUtils");
7+
8+
// getting reference to the html template for the border-radius editor UI
9+
var BorderRadiusTemplate = require("text!BorderRadiusEditorTemplate.html");
10+
11+
function getIndividualValues(values){
12+
// Convert "12px 20px 30px" into an array of individual values like:
13+
// [{num: 12, unit: "px"}, {num: 20, unit: "px"}, ...]
14+
var individualValues = [];
15+
var currentValue;
16+
17+
// We create a new regular expression everytime so that we don't
18+
// reuse stale data from the old RegExp object.
19+
var valueRegex = new RegExp(BorderRadiusUtils.BORDER_RADIUS_SINGLE_VALUE_REGEX);
20+
21+
while ((currentValue = valueRegex.exec(values)) !== null) {
22+
individualValues.push({
23+
num: parseFloat(currentValue[1]),
24+
unit: currentValue[2] || ""
25+
});
26+
}
27+
28+
return individualValues;
29+
}
30+
31+
function BorderRadiusValue($parentElement, location, value, unit, onChange) {
32+
var self = this;
33+
34+
self.value = value || 0;
35+
self.unit = unit || "";
36+
37+
var $slider = this.$slider = $parentElement.find("#" + location + "-slider");
38+
var $unitOptions = $parentElement.find("#" + location + "-radio").children();
39+
var $text = $parentElement.find("#" + location + "-text");
40+
41+
$slider.val(self.value);
42+
$unitOptions.filter(function() {
43+
return $(this).text().trim() === self.unit;
44+
}).addClass("selected");
45+
$text.text(self.toString());
46+
47+
$slider.on("input", function() {
48+
var newValue = $slider.val().trim();
49+
self.value = newValue;
50+
$text.text(self.toString());
51+
onChange();
52+
});
53+
54+
$unitOptions.on("click", function() {
55+
var $selectedUnit = $(this);
56+
$selectedUnit.siblings().removeClass("selected");
57+
$selectedUnit.addClass("selected");
58+
59+
self.unit = $selectedUnit.text().trim();
60+
$text.text(self.toString());
61+
onChange();
62+
});
63+
}
64+
65+
BorderRadiusValue.prototype.toString = function() {
66+
return this.value + (this.value === 0 ? "" : this.unit);
67+
};
68+
69+
function BorderRadiusEditor($parent, valueString, radiusChangeHandler) {
70+
var self = this;
71+
72+
// Create the DOM structure, filling in localized strings via Mustache
73+
self.$element = $(Mustache.render(BorderRadiusTemplate, Strings));
74+
$parent.append(self.$element);
75+
self.radiusChangeHandler = radiusChangeHandler;
76+
77+
this.onChange = this.onChange.bind(this);
78+
self.updateValues(valueString);
79+
80+
// Attach event listeners to toggle the corner mode UI elements
81+
var $individualCornerArea = self.$element.find("#individualCornerArea");
82+
var $individualCornerButton = self.$element.find("#individualCorners");
83+
var $allCornersArea = self.$element.find("#allCornersArea");
84+
var $allCornerButton = self.$element.find("#allCorners");
85+
86+
function toggleCornerOption($showElement, $hideElement) {
87+
$showElement.show();
88+
$hideElement.hide();
89+
self.allCorners = $showElement === $allCornersArea;
90+
self.onChange();
91+
}
92+
93+
$allCornerButton.on("click", function() {
94+
$allCornerButton.addClass("selected");
95+
$individualCornerButton.removeClass("selected");
96+
toggleCornerOption($allCornersArea, $individualCornerArea);
97+
});
98+
$individualCornerButton.on("click", function() {
99+
$allCornerButton.removeClass("selected");
100+
$individualCornerButton.addClass("selected");
101+
toggleCornerOption($individualCornerArea, $allCornersArea);
102+
});
103+
104+
// initialize individual corner editing to be disabled if allCorner is set to true
105+
if(self.allCorners){
106+
$allCornerButton.trigger("click");
107+
} else {
108+
$individualCornerButton.trigger("click");
109+
}
110+
}
111+
112+
BorderRadiusEditor.prototype.updateValues = function(valueString) {
113+
var values = getIndividualValues(valueString);
114+
var numOfValues = values.length;
115+
var firstValue = values[0];
116+
var secondValue = firstValue;
117+
var thirdValue = firstValue;
118+
var fourthValue = firstValue;
119+
120+
this.allCorners = values.length === 1;
121+
122+
if (!this.allCorners) {
123+
secondValue = values[1];
124+
125+
if (numOfValues === 2) {
126+
fourthValue = secondValue;
127+
} else {
128+
thirdValue = values[2];
129+
130+
if (numOfValues === 3) {
131+
fourthValue = secondValue;
132+
} else {
133+
fourthValue = values[3];
134+
}
135+
}
136+
}
137+
138+
this.topLeft = new BorderRadiusValue(
139+
this.$element,
140+
"top-left",
141+
firstValue.num,
142+
firstValue.unit,
143+
this.onChange
144+
);
145+
this.topRight = new BorderRadiusValue(
146+
this.$element,
147+
"top-right",
148+
secondValue.num,
149+
secondValue.unit,
150+
this.onChange
151+
);
152+
this.bottomRight = new BorderRadiusValue(
153+
this.$element,
154+
"bottom-right",
155+
thirdValue.num,
156+
thirdValue.unit,
157+
this.onChange
158+
);
159+
this.bottomLeft = new BorderRadiusValue(
160+
this.$element,
161+
"bottom-left",
162+
fourthValue.num,
163+
fourthValue.unit,
164+
this.onChange
165+
);
166+
this.allCorner = new BorderRadiusValue(
167+
this.$element,
168+
"all-corner",
169+
firstValue.num,
170+
firstValue.unit,
171+
this.onChange
172+
);
173+
174+
//correctly update the values in the UI.
175+
this.onChange();
176+
};
177+
178+
BorderRadiusEditor.prototype.onChange = function() {
179+
if (this.allCorners) {
180+
this.radiusChangeHandler(this.allCorner.toString());
181+
return;
182+
}
183+
184+
var topLeft = this.topLeft.toString();
185+
var topRight = this.topRight.toString();
186+
var bottomRight = this.bottomRight.toString();
187+
var bottomLeft = this.bottomLeft.toString();
188+
var borderRadiusString;
189+
190+
if (topRight === bottomLeft) {
191+
// We can use a two value border radius if top right and
192+
// bottom left are equal and top left and bottom right are equal.
193+
// For e.g. 20px 30px
194+
borderRadiusString = topLeft + " " + topRight;
195+
196+
if (topLeft !== bottomRight) {
197+
// We can use a three value border radius if top right and
198+
// bottom left are equal but the top left and bottom right
199+
// values are not.
200+
borderRadiusString += " " + bottomRight;
201+
} else if (topLeft === topRight) {
202+
// This means that top left and bottom right are equal (set 1),
203+
// the top right and bottom left values are equal (set 2), and
204+
// that set 1 and set 2 are equal - implying that all values
205+
// are the same.
206+
borderRadiusString = topLeft;
207+
}
208+
} else {
209+
borderRadiusString = [topLeft, topRight, bottomRight, bottomLeft].join(" ");
210+
}
211+
212+
this.radiusChangeHandler(borderRadiusString);
213+
};
214+
215+
BorderRadiusEditor.prototype.focus = function() {
216+
this.topLeft.$slider.focus();
217+
};
218+
219+
BorderRadiusEditor.prototype.isValidBorderRadiusString = function(string){
220+
var radiusValueRegEx = new RegExp(BorderRadiusUtils.BORDER_RADIUS_VALUE_REGEX);
221+
return radiusValueRegEx.test(string);
222+
};
223+
224+
exports.BorderRadiusEditor = BorderRadiusEditor;
225+
});
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<div tabindex="-1" class="border-radius-editor">
2+
<header>
3+
<ul class="button-bar">
4+
<li id="allCorners" title="{{ALL_CORNERS}}">
5+
<a href="#" tabindex="0">{{ALL_CORNERS}}</a>
6+
</li>
7+
<li title="{{INDIVIDUAL_CORNERS}}" id="individualCorners">
8+
<a href="#" tabindex="0">{{INDIVIDUAL_CORNERS}}</a>
9+
</li>
10+
</ul>
11+
</header>
12+
13+
<div id="individualCornerArea">
14+
15+
<table>
16+
<tr class="border-radius-input">
17+
<td class="label-container">
18+
<div class="top-left corner-icon"></div>
19+
</td>
20+
<td class="slider-container">
21+
<input id="top-left-slider" type="range" min="0" max="100" step="1">
22+
</td>
23+
<td class="slider-value">
24+
<span class="slider-indicator" id="top-left-text"></span>
25+
</td>
26+
<td class="units-container">
27+
<ul class="button-bar ul-padding-left" id="top-left-radio">
28+
<li id="top-left-radio-px" title="{{PIXEL_UNIT}}"><a href="#" tabindex="0">px</a></li>
29+
<li title="{{PERCENTAGE_UNIT}}" id="top-left-radio-percent"><a href="#" tabindex="0">%</a></li>
30+
<li title="{{EM_UNIT}}" id="top-left-radio-em"><a href="#" tabindex="0">em</a></li>
31+
</ul>
32+
</td>
33+
</tr>
34+
35+
<tr class="border-radius-input">
36+
<td class="label-container">
37+
<div class="top-right corner-icon"></div>
38+
</td>
39+
<td class="slider-container">
40+
<input id="top-right-slider" type="range" min="0" max="100" step="1">
41+
</td>
42+
<td>
43+
<span class="slider-indicator" id="top-right-text"></span>
44+
</td>
45+
<td class="units-container">
46+
<ul class="button-bar ul-padding-left" id="top-right-radio">
47+
<li id="top-right-radio-px" title="{{PIXEL_UNIT}}"><a href="#" tabindex="0">px</a></li>
48+
<li title="{{PERCENTAGE_UNIT}}" id="top-right-radio-percent"><a href="#" tabindex="0">%</a></li>
49+
<li title="{{EM_UNIT}}" id="top-right-radio-em"><a href="#" tabindex="0">em</a></li>
50+
</ul>
51+
</td>
52+
</tr>
53+
54+
<tr class="border-radius-input">
55+
<td class="label-container">
56+
<div class="bottom-right corner-icon"></div>
57+
</td>
58+
<td class="slider-container">
59+
<input id="bottom-right-slider" type="range" min="0" max="100" step="1">
60+
</td>
61+
<td>
62+
<span class="slider-indicator" id="bottom-right-text"></span>
63+
</td>
64+
<td class="units-container">
65+
<ul class="button-bar ul-padding-left" id="bottom-right-radio">
66+
<li id="bottom-right-radio-px" title="{{PIXEL_UNIT}}"><a href="#" tabindex="0">px</a></li>
67+
<li title="{{PERCENTAGE_UNIT}}" id="bottom-right-radio-percent"><a href="#" tabindex="0">%</a></li>
68+
<li title="{{EM_UNIT}}" id="bottom-right-radio-em"><a href="#" tabindex="0">em</a></li>
69+
</ul>
70+
</td>
71+
</tr>
72+
73+
<tr class="border-radius-input">
74+
<td class="label-container">
75+
<div class="bottom-left corner-icon"></div>
76+
</td>
77+
<td class="slider-container">
78+
<input id="bottom-left-slider" type="range" min="0" max="100" step="1">
79+
</td>
80+
<td>
81+
<span class="slider-indicator" id="bottom-left-text"></span>
82+
</td>
83+
<td class="units-container">
84+
<ul class="button-bar ul-padding-left" id="bottom-left-radio">
85+
<li id="bottom-left-radio-px" title="{{PIXEL_UNIT}}"><a href="#" tabindex="0">px</a></li>
86+
<li title="{{PERCENTAGE_UNIT}}" id="bottom-left-radio-percent"><a href="#" tabindex="0">%</a></li>
87+
<li title="{{EM_UNIT}}" id="bottom-left-radio-em"><a href="#" tabindex="0">em</a></li>
88+
</ul>
89+
</td>
90+
</tr>
91+
</table>
92+
</div>
93+
94+
<div id="allCornersArea">
95+
<table>
96+
<tr class="border-radius-input">
97+
<td class="label-container">
98+
<div class="all corner-icon">
99+
<div class="dot"></div>
100+
<div class="dot"></div>
101+
<div class="dot"></div>
102+
<div class="dot"></div>
103+
</div>
104+
</td>
105+
<td class="slider-container">
106+
<input id="all-corner-slider" type="range" min="0" max="100" step="1">
107+
</td>
108+
<td class="slider-value">
109+
<span class="slider-indicator" id="all-corner-text"></span>
110+
</td>
111+
<td class="units-container">
112+
<ul class="button-bar ul-padding-left" id="all-corner-radio">
113+
<li id="all-corner-radio-px" title="{{PIXEL_UNIT}}"><a href="#" tabindex="0">px</a></li>
114+
<li title="{{PERCENTAGE_UNIT}}" id="all-corner-radio-percent"><a href="#" tabindex="0">%</a></li>
115+
<li title="{{EM_UNIT}}" id="all-corner-radio-em"><a href="#" tabindex="0">em</a></li>
116+
</ul>
117+
</td>
118+
</tr>
119+
</table>
120+
<div>
121+
</div>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"border-radius": {"values": ["inherit"]},
3+
"border-top-left-radius": {"values": ["inherit"]},
4+
"border-top-right-radius": {"values": ["inherit"]},
5+
"border-bottom-left-radius": {"values": ["inherit"]},
6+
"border-bottom-right-radius": {"values": ["inherit"]}
7+
}

0 commit comments

Comments
 (0)