]>
Commit | Line | Data |
---|---|---|
24c7594d BB |
1 | (function() { |
2 | var $, SelectListView, TextEditorView, View, fuzzyFilter, _ref, | |
3 | __hasProp = {}.hasOwnProperty, | |
4 | __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; | |
5 | ||
6 | _ref = require('space-pen'), $ = _ref.$, View = _ref.View; | |
7 | ||
8 | TextEditorView = require('./text-editor-view'); | |
9 | ||
10 | fuzzyFilter = null; | |
11 | ||
12 | atom.themes.requireStylesheet(require.resolve('../stylesheets/select-list.less')); | |
13 | ||
14 | module.exports = SelectListView = (function(_super) { | |
15 | __extends(SelectListView, _super); | |
16 | ||
17 | function SelectListView() { | |
18 | return SelectListView.__super__.constructor.apply(this, arguments); | |
19 | } | |
20 | ||
21 | SelectListView.content = function() { | |
22 | return this.div({ | |
23 | "class": 'select-list' | |
24 | }, (function(_this) { | |
25 | return function() { | |
26 | _this.subview('filterEditorView', new TextEditorView({ | |
27 | mini: true | |
28 | })); | |
29 | _this.div({ | |
30 | "class": 'error-message', | |
31 | outlet: 'error' | |
32 | }); | |
33 | _this.div({ | |
34 | "class": 'loading', | |
35 | outlet: 'loadingArea' | |
36 | }, function() { | |
37 | _this.span({ | |
38 | "class": 'loading-message', | |
39 | outlet: 'loading' | |
40 | }); | |
41 | return _this.span({ | |
42 | "class": 'badge', | |
43 | outlet: 'loadingBadge' | |
44 | }); | |
45 | }); | |
46 | return _this.ol({ | |
47 | "class": 'list-group', | |
48 | outlet: 'list' | |
49 | }); | |
50 | }; | |
51 | })(this)); | |
52 | }; | |
53 | ||
54 | SelectListView.prototype.maxItems = Infinity; | |
55 | ||
56 | SelectListView.prototype.scheduleTimeout = null; | |
57 | ||
58 | SelectListView.prototype.inputThrottle = 50; | |
59 | ||
60 | SelectListView.prototype.cancelling = false; | |
61 | ||
62 | ||
63 | /* | |
64 | Section: Construction | |
65 | */ | |
66 | ||
67 | SelectListView.prototype.initialize = function() { | |
68 | this.filterEditorView.getModel().getBuffer().onDidChange((function(_this) { | |
69 | return function() { | |
70 | return _this.schedulePopulateList(); | |
71 | }; | |
72 | })(this)); | |
73 | this.filterEditorView.on('blur', (function(_this) { | |
74 | return function(e) { | |
75 | if (!_this.cancelling) { | |
76 | return _this.cancel(); | |
77 | } | |
78 | }; | |
79 | })(this)); | |
80 | atom.commands.add(this.element, { | |
81 | 'core:move-up': (function(_this) { | |
82 | return function(event) { | |
83 | _this.selectPreviousItemView(); | |
84 | return event.stopPropagation(); | |
85 | }; | |
86 | })(this), | |
87 | 'core:move-down': (function(_this) { | |
88 | return function(event) { | |
89 | _this.selectNextItemView(); | |
90 | return event.stopPropagation(); | |
91 | }; | |
92 | })(this), | |
93 | 'core:move-to-top': (function(_this) { | |
94 | return function(event) { | |
95 | _this.selectItemView(_this.list.find('li:first')); | |
96 | _this.list.scrollToTop(); | |
97 | return event.stopPropagation(); | |
98 | }; | |
99 | })(this), | |
100 | 'core:move-to-bottom': (function(_this) { | |
101 | return function(event) { | |
102 | _this.selectItemView(_this.list.find('li:last')); | |
103 | _this.list.scrollToBottom(); | |
104 | return event.stopPropagation(); | |
105 | }; | |
106 | })(this), | |
107 | 'core:confirm': (function(_this) { | |
108 | return function(event) { | |
109 | _this.confirmSelection(); | |
110 | return event.stopPropagation(); | |
111 | }; | |
112 | })(this), | |
113 | 'core:cancel': (function(_this) { | |
114 | return function(event) { | |
115 | _this.cancel(); | |
116 | return event.stopPropagation(); | |
117 | }; | |
118 | })(this) | |
119 | }); | |
120 | this.list.on('mousedown', (function(_this) { | |
121 | return function(_arg) { | |
122 | var target; | |
123 | target = _arg.target; | |
124 | if (target === _this.list[0]) { | |
125 | return false; | |
126 | } | |
127 | }; | |
128 | })(this)); | |
129 | this.list.on('mousedown', 'li', (function(_this) { | |
130 | return function(e) { | |
131 | _this.selectItemView($(e.target).closest('li')); | |
132 | e.preventDefault(); | |
133 | return false; | |
134 | }; | |
135 | })(this)); | |
136 | return this.list.on('mouseup', 'li', (function(_this) { | |
137 | return function(e) { | |
138 | if ($(e.target).closest('li').hasClass('selected')) { | |
139 | _this.confirmSelection(); | |
140 | } | |
141 | e.preventDefault(); | |
142 | return false; | |
143 | }; | |
144 | })(this)); | |
145 | }; | |
146 | ||
147 | ||
148 | /* | |
149 | Section: Methods that must be overridden | |
150 | */ | |
151 | ||
152 | SelectListView.prototype.viewForItem = function(item) { | |
153 | throw new Error("Subclass must implement a viewForItem(item) method"); | |
154 | }; | |
155 | ||
156 | SelectListView.prototype.confirmed = function(item) { | |
157 | throw new Error("Subclass must implement a confirmed(item) method"); | |
158 | }; | |
159 | ||
160 | ||
161 | /* | |
162 | Section: Managing the list of items | |
163 | */ | |
164 | ||
165 | SelectListView.prototype.setItems = function(items) { | |
166 | this.items = items != null ? items : []; | |
167 | this.populateList(); | |
168 | return this.setLoading(); | |
169 | }; | |
170 | ||
171 | SelectListView.prototype.getSelectedItem = function() { | |
172 | return this.getSelectedItemView().data('select-list-item'); | |
173 | }; | |
174 | ||
175 | SelectListView.prototype.getFilterKey = function() {}; | |
176 | ||
177 | SelectListView.prototype.getFilterQuery = function() { | |
178 | return this.filterEditorView.getText(); | |
179 | }; | |
180 | ||
181 | SelectListView.prototype.setMaxItems = function(maxItems) { | |
182 | this.maxItems = maxItems; | |
183 | }; | |
184 | ||
185 | SelectListView.prototype.populateList = function() { | |
186 | var filterQuery, filteredItems, i, item, itemView, _i, _ref1; | |
187 | if (this.items == null) { | |
188 | return; | |
189 | } | |
190 | filterQuery = this.getFilterQuery(); | |
191 | if (filterQuery.length) { | |
192 | if (fuzzyFilter == null) { | |
193 | fuzzyFilter = require('fuzzaldrin').filter; | |
194 | } | |
195 | filteredItems = fuzzyFilter(this.items, filterQuery, { | |
196 | key: this.getFilterKey() | |
197 | }); | |
198 | } else { | |
199 | filteredItems = this.items; | |
200 | } | |
201 | this.list.empty(); | |
202 | if (filteredItems.length) { | |
203 | this.setError(null); | |
204 | for (i = _i = 0, _ref1 = Math.min(filteredItems.length, this.maxItems); 0 <= _ref1 ? _i < _ref1 : _i > _ref1; i = 0 <= _ref1 ? ++_i : --_i) { | |
205 | item = filteredItems[i]; | |
206 | itemView = $(this.viewForItem(item)); | |
207 | itemView.data('select-list-item', item); | |
208 | this.list.append(itemView); | |
209 | } | |
210 | return this.selectItemView(this.list.find('li:first')); | |
211 | } else { | |
212 | return this.setError(this.getEmptyMessage(this.items.length, filteredItems.length)); | |
213 | } | |
214 | }; | |
215 | ||
216 | ||
217 | /* | |
218 | Section: Messages to the user | |
219 | */ | |
220 | ||
221 | SelectListView.prototype.setError = function(message) { | |
222 | if (message == null) { | |
223 | message = ''; | |
224 | } | |
225 | if (message.length === 0) { | |
226 | return this.error.text('').hide(); | |
227 | } else { | |
228 | this.setLoading(); | |
229 | return this.error.text(message).show(); | |
230 | } | |
231 | }; | |
232 | ||
233 | SelectListView.prototype.setLoading = function(message) { | |
234 | if (message == null) { | |
235 | message = ''; | |
236 | } | |
237 | if (message.length === 0) { | |
238 | this.loading.text(""); | |
239 | this.loadingBadge.text(""); | |
240 | return this.loadingArea.hide(); | |
241 | } else { | |
242 | this.setError(); | |
243 | this.loading.text(message); | |
244 | return this.loadingArea.show(); | |
245 | } | |
246 | }; | |
247 | ||
248 | SelectListView.prototype.getEmptyMessage = function(itemCount, filteredItemCount) { | |
249 | return 'No matches found'; | |
250 | }; | |
251 | ||
252 | ||
253 | /* | |
254 | Section: View Actions | |
255 | */ | |
256 | ||
257 | SelectListView.prototype.cancel = function() { | |
258 | var filterEditorViewFocused; | |
259 | this.list.empty(); | |
260 | this.cancelling = true; | |
261 | filterEditorViewFocused = this.filterEditorView.hasFocus(); | |
262 | if (typeof this.cancelled === "function") { | |
263 | this.cancelled(); | |
264 | } | |
265 | this.filterEditorView.setText(''); | |
266 | if (filterEditorViewFocused) { | |
267 | this.restoreFocus(); | |
268 | } | |
269 | this.cancelling = false; | |
270 | return clearTimeout(this.scheduleTimeout); | |
271 | }; | |
272 | ||
273 | SelectListView.prototype.focusFilterEditor = function() { | |
274 | return this.filterEditorView.focus(); | |
275 | }; | |
276 | ||
277 | SelectListView.prototype.storeFocusedElement = function() { | |
278 | return this.previouslyFocusedElement = $(document.activeElement); | |
279 | }; | |
280 | ||
281 | ||
282 | /* | |
283 | Section: Private | |
284 | */ | |
285 | ||
286 | SelectListView.prototype.selectPreviousItemView = function() { | |
287 | var view; | |
288 | view = this.getSelectedItemView().prev(); | |
289 | if (!view.length) { | |
290 | view = this.list.find('li:last'); | |
291 | } | |
292 | return this.selectItemView(view); | |
293 | }; | |
294 | ||
295 | SelectListView.prototype.selectNextItemView = function() { | |
296 | var view; | |
297 | view = this.getSelectedItemView().next(); | |
298 | if (!view.length) { | |
299 | view = this.list.find('li:first'); | |
300 | } | |
301 | return this.selectItemView(view); | |
302 | }; | |
303 | ||
304 | SelectListView.prototype.selectItemView = function(view) { | |
305 | if (!view.length) { | |
306 | return; | |
307 | } | |
308 | this.list.find('.selected').removeClass('selected'); | |
309 | view.addClass('selected'); | |
310 | return this.scrollToItemView(view); | |
311 | }; | |
312 | ||
313 | SelectListView.prototype.scrollToItemView = function(view) { | |
314 | var desiredBottom, desiredTop, scrollTop; | |
315 | scrollTop = this.list.scrollTop(); | |
316 | desiredTop = view.position().top + scrollTop; | |
317 | desiredBottom = desiredTop + view.outerHeight(); | |
318 | if (desiredTop < scrollTop) { | |
319 | return this.list.scrollTop(desiredTop); | |
320 | } else if (desiredBottom > this.list.scrollBottom()) { | |
321 | return this.list.scrollBottom(desiredBottom); | |
322 | } | |
323 | }; | |
324 | ||
325 | SelectListView.prototype.restoreFocus = function() { | |
326 | var _ref1; | |
327 | return (_ref1 = this.previouslyFocusedElement) != null ? _ref1.focus() : void 0; | |
328 | }; | |
329 | ||
330 | SelectListView.prototype.getSelectedItemView = function() { | |
331 | return this.list.find('li.selected'); | |
332 | }; | |
333 | ||
334 | SelectListView.prototype.confirmSelection = function() { | |
335 | var item; | |
336 | item = this.getSelectedItem(); | |
337 | if (item != null) { | |
338 | return this.confirmed(item); | |
339 | } else { | |
340 | return this.cancel(); | |
341 | } | |
342 | }; | |
343 | ||
344 | SelectListView.prototype.schedulePopulateList = function() { | |
345 | var populateCallback; | |
346 | clearTimeout(this.scheduleTimeout); | |
347 | populateCallback = (function(_this) { | |
348 | return function() { | |
349 | if (_this.isOnDom()) { | |
350 | return _this.populateList(); | |
351 | } | |
352 | }; | |
353 | })(this); | |
354 | return this.scheduleTimeout = setTimeout(populateCallback, this.inputThrottle); | |
355 | }; | |
356 | ||
357 | return SelectListView; | |
358 | ||
359 | })(View); | |
360 | ||
361 | }).call(this); |