Skip to content

Commit 9bfa0fd

Browse files
committed
feat: add search filter capability option in all popups handled via popup manager
1 parent 339870f commit 9bfa0fd

File tree

2 files changed

+138
-3
lines changed

2 files changed

+138
-3
lines changed

src/extensionsIntegrated/RecentProjects/main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,8 @@ define(function (require, exports, module) {
284284
case KeyEvent.DOM_VK_DELETE:
285285
if ($dropdownItem) {
286286
removeSelectedItem(event);
287-
keyHandled = true;
288287
}
288+
keyHandled = true;
289289
break;
290290
}
291291

src/widgets/PopUpManager.js

Lines changed: 137 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ define(function (require, exports, module) {
3434
MainViewManager = require("view/MainViewManager"),
3535
KeyEvent = require("utils/KeyEvent");
3636

37-
let _popUps = [], addPopupInProgress = false;
37+
let _popUps = [], addPopupInProgress = false,
38+
currentEventPopups = [];
3839

3940
/**
4041
* Add Esc key handling for a popup DOM element.
@@ -66,6 +67,26 @@ define(function (require, exports, module) {
6667
addPopupInProgress = false;
6768
}
6869

70+
function handleSelectionEvents($popUp, options = {}) {
71+
const {keyboardEventHandler, enableSearchFilter} = options;
72+
currentEventPopups.push({
73+
$popUp,
74+
keyboardEventHandler,
75+
enableSearchFilter
76+
});
77+
if(currentEventPopups.length > 1){
78+
console.error(`${currentEventPopups.length} popups are visible while handling keyboard events!`,
79+
"Possible popup event handler leak. Only 1 popup event handler is expected at this time.");
80+
}
81+
if(enableSearchFilter && !$popUp.find(".sticky-li-top").length) {
82+
$popUp.prepend(
83+
`<li class="sticky-li-top forced-hidden">
84+
<a class='stylesheet-link'><i class="fa fa-search" aria-hidden="true"></i>&nbsp;&nbsp;
85+
<span class="searchTextSpan"></span></a>
86+
</li>`);
87+
}
88+
}
89+
6990
/**
7091
* Remove Esc key handling for a pop-up. Removes the pop-up from the DOM
7192
* if the pop-up is currently visible and was not originally attached.
@@ -89,6 +110,11 @@ define(function (require, exports, module) {
89110
MainViewManager.focusActivePane();
90111
}
91112

113+
let handlerIndex = currentEventPopups.findIndex(item => item.$popUp.is($popUp));
114+
if(handlerIndex >= 0){
115+
currentEventPopups.splice(handlerIndex, 1);
116+
searchStr = "";
117+
}
92118
// check index after removeHandler is done processing to protect
93119
// against recursive calls
94120
let index = _popUps.indexOf($popUp[0]);
@@ -126,14 +152,122 @@ define(function (require, exports, module) {
126152
}
127153

128154
removePopUp($popUp);
155+
return true;
129156
}
130157

131158
break;
132159
}
133160
}
134161
}
135162

163+
let searchStr ="";
164+
/**
165+
* hides all elements in popup that doesn't match the given search string, also shows the search bar in popup
166+
* @param $popup
167+
* @param searchString
168+
*/
169+
function _filterDropdown($popup, searchString) {
170+
searchStr = searchString;
171+
const $stickyLi = $popup.find('li.sticky-li-top');
172+
if(!$stickyLi.length){
173+
console.error("Search filter element not found! Please call" +
174+
" PopUpManager.handleSelectionEvents with enableSearchFilter option.");
175+
return;
176+
}
177+
if(searchString){
178+
$stickyLi.removeClass("forced-hidden");
179+
} else {
180+
$stickyLi.addClass("forced-hidden");
181+
}
182+
183+
$popup.find('li').each(function(index, li) {
184+
if(index === 0){
185+
// this is the top search box itself
186+
return;
187+
}
188+
const $li = $(li);
189+
if(!$li.text().toLowerCase().includes(searchString.toLowerCase())){
190+
$li.addClass("forced-hidden");
191+
} else {
192+
$li.removeClass("forced-hidden");
193+
}
194+
});
195+
196+
if(searchString) {
197+
$stickyLi.removeClass('forced-hidden');
198+
$stickyLi.find('.searchTextSpan').text(searchString);
199+
} else {
200+
$stickyLi.addClass('forced-hidden');
201+
}
202+
}
203+
204+
function _processSelectionEvent(event) {
205+
const {$popUp, keyboardEventHandler} = currentEventPopups[currentEventPopups.length - 1];
206+
if(!$popUp || !$popUp.is(":visible")){
207+
return false;
208+
}
209+
if(keyboardEventHandler) {
210+
const processed = keyboardEventHandler(event);
211+
if(processed){
212+
return true;
213+
}
214+
}
215+
var keyHandled = false;
216+
217+
switch (event.keyCode) {
218+
case KeyEvent.DOM_VK_UP:
219+
//selectNextItem(-1);
220+
keyHandled = true;
221+
break;
222+
case KeyEvent.DOM_VK_DOWN:
223+
//selectNextItem(+1);
224+
keyHandled = true;
225+
break;
226+
case KeyEvent.DOM_VK_ENTER:
227+
case KeyEvent.DOM_VK_RETURN:
228+
// if ($dropdownItem) {
229+
// $dropdownItem.trigger("click");
230+
// }
231+
keyHandled = true;
232+
break;
233+
}
234+
235+
if(keyHandled){
236+
event.stopImmediatePropagation();
237+
event.preventDefault();
238+
return keyHandled;
239+
} else if((event.ctrlKey || event.metaKey) && event.key === 'v') {
240+
Phoenix.app.clipboardReadText().then(text=>{
241+
searchStr += text;
242+
_filterDropdown($popUp, searchStr);
243+
});
244+
keyHandled = true;
245+
} else if (event.key.length === 1) {
246+
searchStr += event.key;
247+
keyHandled = true;
248+
} else if (event.key === 'Backspace') {
249+
// Remove the last character when Backspace is pressed
250+
searchStr = searchStr.slice(0, -1);
251+
keyHandled = true;
252+
} else {
253+
// bubble up, not for us to handle
254+
return false;
255+
}
256+
_filterDropdown($popUp, searchStr);
257+
258+
if (keyHandled) {
259+
event.stopImmediatePropagation();
260+
event.preventDefault();
261+
}
262+
return keyHandled;
263+
}
264+
136265
function _keydownCaptureListener(keyEvent) {
266+
if(currentEventPopups.length) {
267+
if(_processSelectionEvent(keyEvent)){
268+
return true;
269+
}
270+
}
137271
// Escape key or Alt key (Windows-only)
138272
if (keyEvent.keyCode !== KeyEvent.DOM_VK_ESCAPE &&
139273
!(keyEvent.keyCode === KeyEvent.DOM_VK_ALT && brackets.platform === "win")) {
@@ -145,7 +279,7 @@ define(function (require, exports, module) {
145279
return;
146280
}
147281

148-
removeCurrentPopUp(keyEvent);
282+
return removeCurrentPopUp(keyEvent);
149283
}
150284

151285
/**
@@ -197,6 +331,7 @@ define(function (require, exports, module) {
197331
EventDispatcher.makeEventDispatcher(exports);
198332

199333
exports.addPopUp = addPopUp;
334+
exports.handleSelectionEvents = handleSelectionEvents;
200335
exports.removePopUp = removePopUp;
201336
exports.closeAllPopups = closeAllPopups;
202337
exports.listenToContextMenu = listenToContextMenu;

0 commit comments

Comments
 (0)