Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.

Commit 198a8de

Browse files
committed
Merge pull request #7836 from adobe/rlim/multi-exclusion-set
Implement multiple file exclusion sets
2 parents 6ea2793 + 7d32194 commit 198a8de

11 files changed

Lines changed: 988 additions & 138 deletions

File tree

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<div class="file-filter-dialog modal">
2+
<div class="modal-header">
3+
<h1 class="dialog-title">{{Strings.FILE_FILTER_DIALOG}}</h1>
4+
</div>
5+
<div class="modal-body">
6+
<div class="dialog-message">
7+
{{{instruction}}}
8+
<textarea class="exclusions-editor"></textarea>
9+
<input type="text" class="exclusions-name" placeholder="{{Strings.FILTER_NAME_PLACEHOLDER}}">
10+
<div class="exclusions-filecount">{{Strings.FILTER_COUNTING_FILES}}</div>
11+
</div>
12+
</div>
13+
<div class="modal-footer">
14+
<button class="dialog-button btn" data-button-id="cancel">{{Strings.CANCEL}}</button>
15+
<button class="dialog-button btn primary" data-button-id="ok">{{Strings.OK}}</button>
16+
</div>
17+
</div>

src/htmlContent/filter-name.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<div class='filter-trash-icon'>&times;</div><!--
2+
--><span class='recent-filter-name'>{{{filter-name}}}</span><!--
3+
--><span class='recent-filter-patterns'>{{{filter-patterns}}}</span><!--
4+
--><span class='filter-edit-icon'></span>

src/nls/root/strings.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,14 @@ define({
179179
"ERROR_FETCHING_UPDATE_INFO_MSG" : "There was a problem getting the latest update information from the server. Please make sure you are connected to the internet and try again.",
180180

181181
// File exclusion filters
182-
"NO_FILE_FILTER" : "Exclude files\u2026",
182+
"NEW_FILE_FILTER" : "New Exclusion Set\u2026",
183+
"CLEAR_FILE_FILTER" : "Don't Exclude Files",
184+
"NO_FILE_FILTER" : "No Files Excluded",
185+
"EXCLUDE_FILE_FILTER" : "Exclude {0}",
183186
"EDIT_FILE_FILTER" : "Edit\u2026",
184-
"FILE_FILTER_DIALOG" : "Edit Filter",
187+
"FILE_FILTER_DIALOG" : "Edit Exclusion Set",
185188
"FILE_FILTER_INSTRUCTIONS" : "Exclude files and folders matching any of the following strings / substrings or <a href='{0}' title='{0}'>wildcards</a>. Enter each string on a new line.",
186-
"FILE_FILTER_LIST_PREFIX" : "except",
189+
"FILTER_NAME_PLACEHOLDER" : "Name this exclusion set (optional)",
187190
"FILE_FILTER_CLIPPED_SUFFIX" : "and {0} more",
188191
"FILTER_COUNTING_FILES" : "Counting files\u2026",
189192
"FILTER_FILE_COUNT" : "Allows {0} of {1} files {2}",

src/search/FileFilters.js

Lines changed: 312 additions & 87 deletions
Large diffs are not rendered by default.

src/styles/brackets.less

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,27 +1199,78 @@ a, img {
11991199
}
12001200

12011201
// File exclusion filter (used only in Find in Files search bar, for now)
1202-
.filter-picker {
1203-
display: inline-block;
1204-
margin-left: 8px;
1205-
button {
1206-
margin-left: 8px;
1207-
}
1202+
.filter-trash-icon {
1203+
position: absolute;
1204+
left: 7px;
1205+
width: 16px;
1206+
height: 16px;
1207+
font-size: 20px;
1208+
color: rgba(0, 0, 0, 0.5);
1209+
line-height: 15px;
1210+
text-align: center;
1211+
visibility: hidden;
1212+
}
1213+
1214+
.filter-trash-icon:hover {
1215+
color: rgba(0, 0, 0, 1);
1216+
}
1217+
1218+
.filter-edit-icon {
1219+
float: right;
1220+
width: 13px;
1221+
height: 13px;
1222+
background-image: url("images/edit-icon.svg");
1223+
background-repeat: no-repeat;
1224+
opacity: 0.5;
1225+
visibility: hidden;
1226+
position: relative;
1227+
top: 2px;
1228+
right: -4px;
1229+
}
1230+
1231+
.filter-edit-icon:hover {
1232+
opacity: 1;
1233+
}
1234+
1235+
li:hover .filter-trash-icon,
1236+
li:hover .filter-edit-icon {
1237+
visibility: visible;
1238+
}
1239+
1240+
.recent-filter-name {
1241+
margin-left: 12px;
1242+
}
1243+
1244+
.recent-filter-patterns {
1245+
color: @tc-light-weight-quiet-text;
1246+
padding-right: 52px;
1247+
}
1248+
1249+
button.file-filter-picker {
1250+
margin-left: 10px;
12081251
}
12091252

12101253
// File exclusion filter editor dialog
1211-
textarea.exclusions-editor {
1254+
input.exclusions-name {
12121255
display: block;
12131256
width: 100%;
1214-
height: 160px;
1257+
height: 30px;
12151258
box-sizing: border-box; // needed for width: 100% since it has padding
12161259
margin-top: 12px;
12171260
margin-bottom: 0;
1261+
}
1262+
textarea.exclusions-editor {
1263+
display: block;
1264+
width: 100%;
1265+
height: 120px;
1266+
box-sizing: border-box; // needed for width: 100% since it has padding
1267+
margin-top: 5px;
1268+
margin-bottom: 0;
12181269
.code-font();
12191270
}
12201271
.exclusions-filecount {
1221-
margin: 12px 0 -20px 0;
1222-
padding: 4px 6px;
1272+
margin: 12px 0 -14px 0;
1273+
padding: 4px 8px;
12231274
background-color: @tc-highlight;
12241275
border-radius: @tc-control-border-radius;
12251276
}

src/styles/brackets_patterns_override.less

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ a:focus {
465465
&.dropdown-menu {
466466
border: none;
467467
border-radius: @tc-control-border-radius;
468-
padding: 0;
468+
padding: 5px 0;
469469
position: absolute;
470470
display: block;
471471
box-shadow: @tc-dropdown-shadow;
@@ -478,6 +478,7 @@ a:focus {
478478

479479
&.dropdown-menu li a {
480480
padding: 1px 15px 1px 15px;
481+
color: @bc-black;
481482
}
482483

483484
&.dropdown-menu .stylesheet-link {
@@ -489,8 +490,33 @@ a:focus {
489490
color: @bc-black !important;
490491
}
491492

493+
&.dropdown-menu a {
494+
&::before {
495+
position: absolute;
496+
left: 10px;
497+
text-align: center;
498+
content: "";
499+
display: none;
500+
}
501+
/* toggle checkmark visibility */
502+
&.checked::before {
503+
display: inline-block;
504+
}
505+
}
506+
507+
&.dropdown-menu a:hover {
508+
/* toggle checkmark visibility */
509+
&.checked::before {
510+
display: none;
511+
}
512+
}
513+
492514
&.dropdown-menu a:not(.selected):hover {
493-
background: none;
515+
background: none;
516+
}
517+
518+
.divider {
519+
margin: 5px 1px;
494520
}
495521
}
496522

src/styles/images/edit-icon.svg

Lines changed: 9 additions & 0 deletions
Loading

src/utils/DropdownEventHandler.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,12 @@ define(function (require, exports, module) {
184184
}
185185
}
186186

187-
this._setSelectedIndex(pos, true);
187+
// If the item to be selected is a divider, then rotate one more.
188+
if ($(this.$items[pos]).hasClass("divider")) {
189+
this._rotateSelection((distance > 0) ? (distance + 1) : (distance - 1));
190+
} else {
191+
this._setSelectedIndex(pos, true);
192+
}
188193
};
189194

190195
/**

src/widgets/DropdownButton.js

Lines changed: 94 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,12 @@
3131
* - The button's label is not automatically changed when an item in the list is clicked
3232
* - Its width is not the max of all the dropdown items' labels
3333
* - The button & dropdown's appearance can be customized far more
34+
* Events
35+
* - listRendered -- This event is dispatched after the entire list is rendered so that custom event handlers can be
36+
* set up for any custom UI in the list.
3437
*
3538
* TODO: merge DropdownEventHandler into this? Are there any other widgets that might want to use it separately?
39+
*
3640
*/
3741
define(function (require, exports, module) {
3842
"use strict";
@@ -98,6 +102,17 @@ define(function (require, exports, module) {
98102
event.stopPropagation();
99103
};
100104

105+
/**
106+
* Update the button label.
107+
* @param {string} label
108+
*/
109+
DropdownButton.prototype.setButtonLabel = function (label) {
110+
if (!this.$button) {
111+
return;
112+
}
113+
$(this.$button).text(label);
114+
};
115+
101116
/**
102117
* Called for each item when rendering the dropdown.
103118
* @param {*} item from items array
@@ -108,17 +123,69 @@ define(function (require, exports, module) {
108123
return _.escape(String(item));
109124
};
110125

111-
/** Converts the list of item objects into HTML list items in format required by DropdownEventHandler */
112-
DropdownButton.prototype._renderList = function () {
126+
/**
127+
* Converts the list of item objects into HTML list items in format required by DropdownEventHandler
128+
* @param {!jQueryObject} parent The dropdown element
129+
* @return {!jQueryObject} The dropdown element with the rendered list items appended.
130+
*/
131+
DropdownButton.prototype._renderList = function (parent) {
132+
if (!parent) {
133+
return null;
134+
}
135+
113136
var html = "";
114137
this.items.forEach(function (item, i) {
115-
html += "<li><a class='stylesheet-link' data-index='" + i + "'>";
116-
html += this.itemRenderer(item, i);
117-
html += "</a></li>";
138+
if (item === "---") {
139+
html += "<li class='divider'></li>";
140+
} else {
141+
html += "<li><a class='stylesheet-link' data-index='" + i + "'>";
142+
html += this.itemRenderer(item, i);
143+
html += "</a></li>";
144+
}
118145
}.bind(this));
119-
return html;
146+
147+
parent.append(html);
148+
149+
// Also trigger listRendered handler so that custom event handlers can be
150+
// set up for any custom UI in the list.
151+
$(this).triggerHandler("listRendered", [parent]);
152+
153+
return parent;
120154
};
121155

156+
/**
157+
* Refresh the dropdown list by removing and re-creating all list items.
158+
* Call this after deleting/adding any item in the dropdown list.
159+
*/
160+
DropdownButton.prototype.refresh = function () {
161+
if (!this.$dropdown) {
162+
return;
163+
}
164+
165+
// Remove all list items and then re-create them from this.items.
166+
$("li", this.$dropdown).remove();
167+
this._renderList(this.$dropdown);
168+
};
169+
170+
/**
171+
* Check/Uncheck the list item of the given index.
172+
* @param {number} index The index of the list item to be checked or unchecked
173+
* @param {boolean} checked True if the list item is to be checked, false to get check
174+
* mark removed.
175+
*/
176+
DropdownButton.prototype.setChecked = function (index, checked) {
177+
if (!this.$dropdown) {
178+
return;
179+
}
180+
181+
var listItems = $("li", this.$dropdown),
182+
count = listItems.length;
183+
184+
if (index > -1 && index < count) {
185+
$("a", listItems[index]).toggleClass("checked", checked);
186+
}
187+
};
188+
122189
/** Pops open the dropdown if currently closed. Does nothing if items.length == 0 */
123190
DropdownButton.prototype.showDropdown = function () {
124191
// Act like a plain old button if no items to show
@@ -133,20 +200,22 @@ define(function (require, exports, module) {
133200
Menus.closeAll();
134201

135202
var $dropdown = $("<ul class='dropdown-menu dropdownbutton-popup' tabindex='-1'>")
136-
.addClass(this.dropdownExtraClasses) // (no-op if unspecified)
137-
.append(this._renderList())
203+
.addClass(this.dropdownExtraClasses); // (no-op if unspecified)
204+
205+
this.$dropdown = $dropdown;
206+
this._renderList(this.$dropdown)
138207
.appendTo($("body"))
139208
.data("attached-to", this.$button[0]); // keep ModalBar open while dropdown focused
140209

141210
// Calculate position of dropdown
142-
var toggleOffset = this.$button.offset(),
143-
posLeft = toggleOffset.left,
144-
posTop = toggleOffset.top + this.$button.outerHeight(),
145-
elementRect = {
146-
top: posTop,
147-
left: posLeft,
148-
height: $dropdown.height(),
149-
width: $dropdown.width()
211+
var toggleOffset = this.$button.offset(),
212+
posLeft = toggleOffset.left,
213+
posTop = toggleOffset.top + this.$button.outerHeight(),
214+
elementRect = {
215+
top: posTop,
216+
left: posLeft,
217+
height: $dropdown.height(),
218+
width: $dropdown.width()
150219
},
151220
clip = ViewUtils.getElementClipSize($(window), elementRect);
152221

@@ -170,14 +239,12 @@ define(function (require, exports, module) {
170239
this._dropdownEventHandler = new DropdownEventHandler($dropdown, this._onSelect.bind(this), this._onDropdownClose.bind(this));
171240
this._dropdownEventHandler.open();
172241

173-
window.document.body.addEventListener("click", this._onClickOutside, true);
242+
window.document.body.addEventListener("mousedown", this._onClickOutside, true);
174243
$(PanelManager).on("editorAreaResize", this.closeDropdown);
175244

176245
// Manage focus
177246
this._lastFocus = window.document.activeElement;
178247
$dropdown.focus();
179-
180-
this.$dropdown = $dropdown;
181248
};
182249

183250
/**
@@ -186,14 +253,14 @@ define(function (require, exports, module) {
186253
* was closed.
187254
*/
188255
DropdownButton.prototype._onDropdownClose = function () {
189-
window.document.body.removeEventListener("click", this._onClickOutside, true);
256+
window.document.body.removeEventListener("mousedown", this._onClickOutside, true);
190257
$(PanelManager).off("editorAreaResize", this.closeDropdown);
191-
258+
192259
// Restore focus to old pos, unless "select" handler changed it
193260
if (window.document.activeElement === this.$dropdown[0]) {
194261
this._lastFocus.focus();
195262
}
196-
263+
197264
this._dropdownEventHandler = null;
198265
this.$dropdown = null; // already remvoed from DOM automatically by PopUpManager
199266
};
@@ -209,9 +276,12 @@ define(function (require, exports, module) {
209276
DropdownButton.prototype._onClickOutside = function (event) {
210277
var $container = $(event.target).closest(".dropdownbutton-popup");
211278

212-
// If click is outside dropdown list, then close dropdown list
213-
if ($container.length === 0 || $container[0] !== this.$dropdown[0]) {
279+
// If click is outside dropdown list or dropdown button, then close dropdown list
280+
if (!$(event.target).is(this.$button) &&
281+
($container.length === 0 || $container[0] !== this.$dropdown[0])) {
214282
this.closeDropdown();
283+
event.stopPropagation();
284+
event.preventDefault();
215285
}
216286
};
217287

0 commit comments

Comments
 (0)