362 lines
10 KiB
JavaScript
362 lines
10 KiB
JavaScript
|
|
(function() {
|
||
|
|
var $, SelectListView, TextEditorView, View, fuzzyFilter, _ref,
|
||
|
|
__hasProp = {}.hasOwnProperty,
|
||
|
|
__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; };
|
||
|
|
|
||
|
|
_ref = require('space-pen'), $ = _ref.$, View = _ref.View;
|
||
|
|
|
||
|
|
TextEditorView = require('./text-editor-view');
|
||
|
|
|
||
|
|
fuzzyFilter = null;
|
||
|
|
|
||
|
|
atom.themes.requireStylesheet(require.resolve('../stylesheets/select-list.less'));
|
||
|
|
|
||
|
|
module.exports = SelectListView = (function(_super) {
|
||
|
|
__extends(SelectListView, _super);
|
||
|
|
|
||
|
|
function SelectListView() {
|
||
|
|
return SelectListView.__super__.constructor.apply(this, arguments);
|
||
|
|
}
|
||
|
|
|
||
|
|
SelectListView.content = function() {
|
||
|
|
return this.div({
|
||
|
|
"class": 'select-list'
|
||
|
|
}, (function(_this) {
|
||
|
|
return function() {
|
||
|
|
_this.subview('filterEditorView', new TextEditorView({
|
||
|
|
mini: true
|
||
|
|
}));
|
||
|
|
_this.div({
|
||
|
|
"class": 'error-message',
|
||
|
|
outlet: 'error'
|
||
|
|
});
|
||
|
|
_this.div({
|
||
|
|
"class": 'loading',
|
||
|
|
outlet: 'loadingArea'
|
||
|
|
}, function() {
|
||
|
|
_this.span({
|
||
|
|
"class": 'loading-message',
|
||
|
|
outlet: 'loading'
|
||
|
|
});
|
||
|
|
return _this.span({
|
||
|
|
"class": 'badge',
|
||
|
|
outlet: 'loadingBadge'
|
||
|
|
});
|
||
|
|
});
|
||
|
|
return _this.ol({
|
||
|
|
"class": 'list-group',
|
||
|
|
outlet: 'list'
|
||
|
|
});
|
||
|
|
};
|
||
|
|
})(this));
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.maxItems = Infinity;
|
||
|
|
|
||
|
|
SelectListView.prototype.scheduleTimeout = null;
|
||
|
|
|
||
|
|
SelectListView.prototype.inputThrottle = 50;
|
||
|
|
|
||
|
|
SelectListView.prototype.cancelling = false;
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Section: Construction
|
||
|
|
*/
|
||
|
|
|
||
|
|
SelectListView.prototype.initialize = function() {
|
||
|
|
this.filterEditorView.getModel().getBuffer().onDidChange((function(_this) {
|
||
|
|
return function() {
|
||
|
|
return _this.schedulePopulateList();
|
||
|
|
};
|
||
|
|
})(this));
|
||
|
|
this.filterEditorView.on('blur', (function(_this) {
|
||
|
|
return function(e) {
|
||
|
|
if (!(_this.cancelling || !document.hasFocus())) {
|
||
|
|
return _this.cancel();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
})(this));
|
||
|
|
atom.commands.add(this.element, {
|
||
|
|
'core:move-up': (function(_this) {
|
||
|
|
return function(event) {
|
||
|
|
_this.selectPreviousItemView();
|
||
|
|
return event.stopPropagation();
|
||
|
|
};
|
||
|
|
})(this),
|
||
|
|
'core:move-down': (function(_this) {
|
||
|
|
return function(event) {
|
||
|
|
_this.selectNextItemView();
|
||
|
|
return event.stopPropagation();
|
||
|
|
};
|
||
|
|
})(this),
|
||
|
|
'core:move-to-top': (function(_this) {
|
||
|
|
return function(event) {
|
||
|
|
_this.selectItemView(_this.list.find('li:first'));
|
||
|
|
_this.list.scrollToTop();
|
||
|
|
return event.stopPropagation();
|
||
|
|
};
|
||
|
|
})(this),
|
||
|
|
'core:move-to-bottom': (function(_this) {
|
||
|
|
return function(event) {
|
||
|
|
_this.selectItemView(_this.list.find('li:last'));
|
||
|
|
_this.list.scrollToBottom();
|
||
|
|
return event.stopPropagation();
|
||
|
|
};
|
||
|
|
})(this),
|
||
|
|
'core:confirm': (function(_this) {
|
||
|
|
return function(event) {
|
||
|
|
_this.confirmSelection();
|
||
|
|
return event.stopPropagation();
|
||
|
|
};
|
||
|
|
})(this),
|
||
|
|
'core:cancel': (function(_this) {
|
||
|
|
return function(event) {
|
||
|
|
_this.cancel();
|
||
|
|
return event.stopPropagation();
|
||
|
|
};
|
||
|
|
})(this)
|
||
|
|
});
|
||
|
|
this.list.on('mousedown', (function(_this) {
|
||
|
|
return function(_arg) {
|
||
|
|
var target;
|
||
|
|
target = _arg.target;
|
||
|
|
if (target === _this.list[0]) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
})(this));
|
||
|
|
this.list.on('mousedown', 'li', (function(_this) {
|
||
|
|
return function(e) {
|
||
|
|
_this.selectItemView($(e.target).closest('li'));
|
||
|
|
e.preventDefault();
|
||
|
|
return false;
|
||
|
|
};
|
||
|
|
})(this));
|
||
|
|
return this.list.on('mouseup', 'li', (function(_this) {
|
||
|
|
return function(e) {
|
||
|
|
if ($(e.target).closest('li').hasClass('selected')) {
|
||
|
|
_this.confirmSelection();
|
||
|
|
}
|
||
|
|
e.preventDefault();
|
||
|
|
return false;
|
||
|
|
};
|
||
|
|
})(this));
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Section: Methods that must be overridden
|
||
|
|
*/
|
||
|
|
|
||
|
|
SelectListView.prototype.viewForItem = function(item) {
|
||
|
|
throw new Error("Subclass must implement a viewForItem(item) method");
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.confirmed = function(item) {
|
||
|
|
throw new Error("Subclass must implement a confirmed(item) method");
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Section: Managing the list of items
|
||
|
|
*/
|
||
|
|
|
||
|
|
SelectListView.prototype.setItems = function(items) {
|
||
|
|
this.items = items != null ? items : [];
|
||
|
|
this.populateList();
|
||
|
|
return this.setLoading();
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.getSelectedItem = function() {
|
||
|
|
return this.getSelectedItemView().data('select-list-item');
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.getFilterKey = function() {};
|
||
|
|
|
||
|
|
SelectListView.prototype.getFilterQuery = function() {
|
||
|
|
return this.filterEditorView.getText();
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.setMaxItems = function(maxItems) {
|
||
|
|
this.maxItems = maxItems;
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.populateList = function() {
|
||
|
|
var filterQuery, filteredItems, i, item, itemView, _i, _ref1;
|
||
|
|
if (this.items == null) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
filterQuery = this.getFilterQuery();
|
||
|
|
if (filterQuery.length) {
|
||
|
|
if (fuzzyFilter == null) {
|
||
|
|
fuzzyFilter = require('fuzzaldrin').filter;
|
||
|
|
}
|
||
|
|
filteredItems = fuzzyFilter(this.items, filterQuery, {
|
||
|
|
key: this.getFilterKey()
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
filteredItems = this.items;
|
||
|
|
}
|
||
|
|
this.list.empty();
|
||
|
|
if (filteredItems.length) {
|
||
|
|
this.setError(null);
|
||
|
|
for (i = _i = 0, _ref1 = Math.min(filteredItems.length, this.maxItems); 0 <= _ref1 ? _i < _ref1 : _i > _ref1; i = 0 <= _ref1 ? ++_i : --_i) {
|
||
|
|
item = filteredItems[i];
|
||
|
|
itemView = $(this.viewForItem(item));
|
||
|
|
itemView.data('select-list-item', item);
|
||
|
|
this.list.append(itemView);
|
||
|
|
}
|
||
|
|
return this.selectItemView(this.list.find('li:first'));
|
||
|
|
} else {
|
||
|
|
return this.setError(this.getEmptyMessage(this.items.length, filteredItems.length));
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Section: Messages to the user
|
||
|
|
*/
|
||
|
|
|
||
|
|
SelectListView.prototype.setError = function(message) {
|
||
|
|
if (message == null) {
|
||
|
|
message = '';
|
||
|
|
}
|
||
|
|
if (message.length === 0) {
|
||
|
|
return this.error.text('').hide();
|
||
|
|
} else {
|
||
|
|
this.setLoading();
|
||
|
|
return this.error.text(message).show();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.setLoading = function(message) {
|
||
|
|
if (message == null) {
|
||
|
|
message = '';
|
||
|
|
}
|
||
|
|
if (message.length === 0) {
|
||
|
|
this.loading.text("");
|
||
|
|
this.loadingBadge.text("");
|
||
|
|
return this.loadingArea.hide();
|
||
|
|
} else {
|
||
|
|
this.setError();
|
||
|
|
this.loading.text(message);
|
||
|
|
return this.loadingArea.show();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.getEmptyMessage = function(itemCount, filteredItemCount) {
|
||
|
|
return 'No matches found';
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Section: View Actions
|
||
|
|
*/
|
||
|
|
|
||
|
|
SelectListView.prototype.cancel = function() {
|
||
|
|
var filterEditorViewFocused;
|
||
|
|
this.list.empty();
|
||
|
|
this.cancelling = true;
|
||
|
|
filterEditorViewFocused = this.filterEditorView.hasFocus();
|
||
|
|
if (typeof this.cancelled === "function") {
|
||
|
|
this.cancelled();
|
||
|
|
}
|
||
|
|
this.filterEditorView.setText('');
|
||
|
|
if (filterEditorViewFocused) {
|
||
|
|
this.restoreFocus();
|
||
|
|
}
|
||
|
|
this.cancelling = false;
|
||
|
|
return clearTimeout(this.scheduleTimeout);
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.focusFilterEditor = function() {
|
||
|
|
return this.filterEditorView.focus();
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.storeFocusedElement = function() {
|
||
|
|
return this.previouslyFocusedElement = $(document.activeElement);
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Section: Private
|
||
|
|
*/
|
||
|
|
|
||
|
|
SelectListView.prototype.selectPreviousItemView = function() {
|
||
|
|
var view;
|
||
|
|
view = this.getSelectedItemView().prev();
|
||
|
|
if (!view.length) {
|
||
|
|
view = this.list.find('li:last');
|
||
|
|
}
|
||
|
|
return this.selectItemView(view);
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.selectNextItemView = function() {
|
||
|
|
var view;
|
||
|
|
view = this.getSelectedItemView().next();
|
||
|
|
if (!view.length) {
|
||
|
|
view = this.list.find('li:first');
|
||
|
|
}
|
||
|
|
return this.selectItemView(view);
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.selectItemView = function(view) {
|
||
|
|
if (!view.length) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
this.list.find('.selected').removeClass('selected');
|
||
|
|
view.addClass('selected');
|
||
|
|
return this.scrollToItemView(view);
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.scrollToItemView = function(view) {
|
||
|
|
var desiredBottom, desiredTop, scrollTop;
|
||
|
|
scrollTop = this.list.scrollTop();
|
||
|
|
desiredTop = view.position().top + scrollTop;
|
||
|
|
desiredBottom = desiredTop + view.outerHeight();
|
||
|
|
if (desiredTop < scrollTop) {
|
||
|
|
return this.list.scrollTop(desiredTop);
|
||
|
|
} else if (desiredBottom > this.list.scrollBottom()) {
|
||
|
|
return this.list.scrollBottom(desiredBottom);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.restoreFocus = function() {
|
||
|
|
var _ref1;
|
||
|
|
return (_ref1 = this.previouslyFocusedElement) != null ? _ref1.focus() : void 0;
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.getSelectedItemView = function() {
|
||
|
|
return this.list.find('li.selected');
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.confirmSelection = function() {
|
||
|
|
var item;
|
||
|
|
item = this.getSelectedItem();
|
||
|
|
if (item != null) {
|
||
|
|
return this.confirmed(item);
|
||
|
|
} else {
|
||
|
|
return this.cancel();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
SelectListView.prototype.schedulePopulateList = function() {
|
||
|
|
var populateCallback;
|
||
|
|
clearTimeout(this.scheduleTimeout);
|
||
|
|
populateCallback = (function(_this) {
|
||
|
|
return function() {
|
||
|
|
if (_this.isOnDom()) {
|
||
|
|
return _this.populateList();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
})(this);
|
||
|
|
return this.scheduleTimeout = setTimeout(populateCallback, this.inputThrottle);
|
||
|
|
};
|
||
|
|
|
||
|
|
return SelectListView;
|
||
|
|
|
||
|
|
})(View);
|
||
|
|
|
||
|
|
}).call(this);
|